1.1.背景
当我们通过RestTemplate调用其它服务的API时,所需要的参数须在请求的URL中进行拼接,如果参数少的话或许我们还可以忍受,一旦有多个参数的话,这时拼接请求字符串就会效率低下,并且显得好傻。
那么有没有更好的解决方案呢?答案是确定的有,Netflix已经为我们提供了一个框架:Feign。
1.2.Feign概述
Feign是Spring Cloud提供的声明式、模板化的HTTP客户端, 它使得调用远程服务就像调用本地服务一样简单,只需要创建一个接口并添加一个注解即可。
Spring Cloud集成Feign并对其进行了增强,使Feign支持了Spring MVC注解;Feign默认集成了Ribbon,所以Fegin默认就实现了负载均衡的效果。
1.3.Feign入门

1.3.1.创建服务提供者
1.3.1.1.创建工程
????????
1.3.1.2.application.yml
server:
port: 9091
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.128.131:8848 #nacos服务的地址
application:
name: feign-provider #向注册中心注册的名字
?pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springCloud_parent</artifactId>
<groupId>com.peng</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>feign_provider01</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--nacos客户端-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.peng</groupId>
<artifactId>springcloud_commom</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
controller
package com.peng.controller;
import com.peng.pojo.User;
import com.peng.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/provider")
public class ProviderController {
@Autowired
private UserService userService;
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable Integer id){
return userService.getUserById(id);
}
@RequestMapping("/deleteUserById")
public User deleteUserById(@RequestParam("id") Integer id){
return userService.deleteUserById(id);
}
@RequestMapping("/addUser")
public User addUser(@RequestBody User user){
return userService.addUser(user);
}
}
service
package com.peng.service;
import com.peng.pojo.User;
public interface UserService {
User getUserById(Integer id);
User deleteUserById(Integer id);
User addUser(User user);
}
impl
package com.peng.service.impl;
import com.peng.pojo.User;
import com.peng.service.UserService;
import org.springframework.stereotype.Service;
@Service
public class UserServiceImpl implements UserService {
@Override
public User getUserById(Integer id) {
return new User(id,"张三-01",12);
}
@Override
public User deleteUserById(Integer id) {
return new User(id,"删除了张三-01",12);
}
@Override
public User addUser(User user) {
return new User(22,"新增了张三-01",12);
}
}
启动类
package com.peng;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient //向注册中心注册该服务,并可以获取其他服务的调用地址
public class SpringCloudProviderApp {
public static void main(String[] args) {
SpringApplication.run(SpringCloudProviderApp.class,args);
}
}
1.3.2.创建feign接口
1.3.2.1.创建工程

pom文件
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>com.peng</groupId>
<artifactId>springcloud_commom</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
?
1.3.2.3.feign在接口中使用
1、@RequestMapping表示 拼接请求路径? ? ?localhost:80/getUser/1
2、@PathVariable("id") 表示? ?传参????????????????localhost:80/getUser?id=1
3、@RequestBody? ?对象转JSON传参? ? ? ? ? ?localhost:80/getUser?id=1&name=zs? ? ?转成JSON
package com.peng.feign;
import com.peng.pojo.User;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
@FeignClient("feign-provider") //调用的服务名
@RequestMapping("/provider") //拼接路径
public interface UserServiceFeign {
@RequestMapping("/getUserById/{id}") //拼接url
User getUserById(@PathVariable("id") Integer id); //restful形式拼接参数
@RequestMapping("/deleteUserById") //拼接url
User deleteUserById(@RequestParam("id") Integer id);//?形式拼接参数
@RequestMapping("/addUser") //拼接url
User addUser(@RequestBody User user); //pojo ==> json 把传过来的参数转成json串
}
1.3.3.创建服务消费者
1.3.3.1.创建工程

1.3.3.2.pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springCloud_parent</artifactId>
<groupId>com.peng</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>feign_consumer</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--nacos-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<dependency>
<groupId>com.peng</groupId>
<artifactId>feign_interface</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
</dependencies>
</project>
1.3.3.3.application.yml
server:
port: 80
compression:
enabled: true #开启gzip压缩
spring:
cloud:
nacos:
discovery:
server-addr: 192.168.128.131:8848 #向nacos中心注册服务(nacos服务的地址)
application:
name: feign-consumer #给该服务起个名字
1.3.3.4.Controller
package com.peng.controller;
import com.peng.feign.UserServiceFeign;
import com.peng.pojo.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/consumer")
public class ConsumerController {
//访问Rest服务的客户端
@Autowired
private UserServiceFeign userServiceFeign; //注入代理类
@RequestMapping("/getUserById/{id}")
public User getUserById(@PathVariable Integer id){
//打印代理类的类型
System.out.println(userServiceFeign.getClass());
return userServiceFeign.getUserById(id);
}
@RequestMapping("/deleteUserById")
public User deleteUserById(@RequestParam("id") Integer id){
//打印代理类的类型
System.out.println(userServiceFeign.getClass());
return userServiceFeign.deleteUserById(id);
}
@RequestMapping("/addUser")
public User addUser(User user){
//打印代理类的类型
System.out.println(userServiceFeign.getClass());
return userServiceFeign.addUser(user);
}
}
配置类
package com.peng.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;
@Configuration
public class ConfigBean {
@Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
1.3.3.4.app(启动类)
package com.peng;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
import org.springframework.cloud.openfeign.EnableFeignClients;
@SpringBootApplication
@EnableDiscoveryClient //向Nacos 注册中心注册该服务,并可以获取其他服务的调用地址
@EnableFeignClients //开启feign注解扫描
public class SpringCloudConsumerApp {
public static void main(String[] args) {
SpringApplication.run(SpringCloudConsumerApp.class,args);
}
}
测试:三种方式访问
第一种:对象

第二种:路径传参

第三种:路径拼接传参,key=value

1.4.Feign原理
1.4.1、将feign接口的代理类扫描到Spring容器中: ?? ??? ?@EnableFeignClients开启feign注解扫描:FeignClientsRegistrar.registerFeignClients()扫描被 @FeignClient标识的接口生成代理类, ?? ??? ?并把接口和代理类交给Spring的容器管理。 ?1.4.2、为接口的方法创建RequestTemplate ?? ??? ?当consumer调用feign代理类时,代理类会调用SynchronousMethodHandler.invoke()创建RequestTemplate(url,参数) ?1.4.3、发出请求 ?? ??? ?代理类会通过RequestTemplate创建Request,然后client(URLConnetct、HttpClient、OkHttp)使用Request发送请求
?1.5feign优化
1.5.1、开启feign日志
?? ??? ?feign: ?? ??? ? ?client: ?? ??? ? ? ?config: ?? ??? ? ? ? ?default: ?? ??? ??? ?loggerLevel: full ?? ??? ?logging: ?? ??? ? ?level: ?? ??? ? ? ?com.peng.feign: debug

?
?? ?1.5.2、feign超时
?? ??? ?1、方式一: ?? ??? ??? ?ribbon: ?? ??? ??? ? ? ConnectTimeout: 5000 #请求连接的超时时间 ?? ??? ??? ? ? ReadTimeout: 5000 #请求处理的超时时间 ?? ??? ?2、方式二: ?? ??? ??? ?feign: ?? ??? ??? ? ?client: ?? ??? ??? ? ? ?config: ?? ??? ??? ? ? ? ?feign-provider: ?? ??? ??? ??? ?ConnectTimeout: 5000 #请求连接的超时时间 ?? ??? ??? ??? ?ReadTimeout: 5000 #请求处理的超时时间
不配置的话默认是一秒,超过一秒就会抛异常,可以配置连接超时时间,当开启日志时,会忽略连接超时
 ?? ?1.5.3、http连接池
?? ??? ?<dependency> ?? ??? ? ? ?<groupId>io.github.openfeign</groupId> ?? ??? ? ? ?<artifactId>feign-httpclient</artifactId> ?? ??? ?</dependency>
 ?? ?1.5.4、gzip压缩
??? ??? ?server: ?? ??? ? ?compression: ?? ??? ? ? ? ?enabled: true #开启gzip压缩

?

?
?
?
|