知识点:
OpenFeign源于Netflix的Feign,是http通信的客户端。屏蔽了网络通信的细节,直接面向接口的方式开发,让开发者感知不到网络通信细节。 所有远程调用,都像调用本地方法一样完成!
OpenFeign 是 Spring Cloud 对 Feign 的二次封装,它具有 Feign 的所有功能,并在 Feign 的基础上增加了对 Spring MVC 注解的支持,例如 @RequestMapping、@GetMapping 和 @PostMapping 等。
OpenFeign 对 Ribbon进行了集成,利用 Ribbon 维护了一份可用服务清单,并通过 Ribbon 实现了客户端的负载均衡。
注解 | 说明 |
---|---|
@FeignClient | 该注解用于通知 OpenFeign 组件对 @RequestMapping 注解下的接口进行解析,并通过动态代理的方式产生实现类,实现负载均衡和服务调用。 |
@EnableFeignClients | 该注解用于开启 OpenFeign 功能(一般使用在SpringBoot启动类上),当 Spring Cloud 应用启动时,OpenFeign 会扫描标有 @FeignClient 注解的接口,生成代理并注册到 Spring 容器中。 |
@RequestMapping | Spring MVC 注解,在 Spring MVC 中使用该注解映射请求,通过它来指定控制器(Controller)可以处理哪些 URL 请求,相当于 Servlet 中 web.xml 的配置。 |
@GetMapping | Spring MVC 注解,用来映射 GET 请求,它是一个组合注解,相当于 @RequestMapping(method = RequestMethod.GET) 。 |
@PostMapping | Spring MVC 注解,用来映射 POST 请求,它是一个组合注解,相当于 @RequestMapping(method = RequestMethod.POST) 。 |
引入pom依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
创建Api接口
public interface IPromotionService {
@GetMapping("/promotion")
public String promotion();
}
创建feignClient接口
@FeignClient(name = "marking-service") // 这里FeignClient注解会被扫描
public interface IPromotionServiceClient extends IPromotionService {
}
引入pom依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>com.fangergroupId>
<artifactId>provider-apiartifactId>
dependency>
创建API接口实现
@Slf4j
@RestController
@RequestMapping("/promotion")
public class PromotionController implements IPromotionService {
@GetMapping
public String promotion(){
return "promotion-info SUCCESS";
}
}
application.properties
server.port=9091
spring.application.name=provider-service
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
consumer-service是OpenFeign接口的调用方
引入pom依赖
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-eureka-clientartifactId>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-netflix-ribbonartifactId>
<version>2.2.9.RELEASEversion>
dependency>
<dependency>
<groupId>org.springframework.cloudgroupId>
<artifactId>spring-cloud-starter-openfeignartifactId>
dependency>
<dependency>
<groupId>com.fangergroupId>
<artifactId>provider-apiartifactId>
dependency>
启动类配置
// 开启OpenFeign,并配置扫描路径,provider-api中feignClient接口的类路径
@EnableFeignClients(basePackages = "com.fanger.mall.feignclient")
@SpringBootApplication
public class ConsumerServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerServiceApplication.class, args);
}
}
application.properties
server.port=8080
spring.application.name=ConsumerService
eureka.client.service-url.defaultZone=http://localhost:8761/eureka
Controller接口
@Slf4j
@RestController
public class PromotionController {
// 这里注入代理类
@Autowired
IPromotionService iPromotionService;
@PostMapping("/promotion")
public String login(){
// 这里直接类似本地调用的方式来执行
return iPromotionService.promotion();
}
}
开启压缩可以有效节约网络资源,但是会增加CPU压力,建议把最小压缩的文档大小适度调大一点
#开启压缩可以有效节约网络资源,但是会增加CPU压力,建议把最小压缩的文档大小适度调大一点
#开启gzip 压缩协议
feign.compression.request.enabled=false
#响应也开启gzip压缩传输协议
feign.compression.response.enabled=true
#最小压缩文件大小为2048m
feign.compression.request.min-request-size=2048
#请求数据格式
feign.compression.request.mime-types=text/xml, application/xml, application/json
a. 创建config类
@Configuration
public class FeignLogConfig {
@Bean
Logger.Level feignLogger(){
Logger.Level full = Logger.Level.FULL; //全部日志
Logger.Level none = Logger.Level.NONE; //不记录日志
Logger.Level basic = Logger.Level.BASIC; //除了headers日志
Logger.Level headers = Logger.Level.HEADERS; //headers 日志
return full;
}
}
b.需要记录日志处引用FeignLogConfig 类
@FeignClient(name = "eureka-product-service",configuration = FeignLogConfig.class)
public interface IHelloControllerFeign {
@GetMapping("/hello")
String sayHello();
}
c. application.properties 配置需要记录日志文件的日志级别
#设置feign日志级别
logging.level.[com.example.demo.service.IHelloControllerFeign]=debug
默认远程访问协议为jdk自带的sun.net.www.protocol.http.HttpURLConnection
效率低,可改为okHttp
a.添加OKhttp依赖
<dependency>
<groupId>io.github.openfeigngroupId>
<artifactId>feign-okhttpartifactId>
dependency>
b.application.properties 配置,关闭默认的sun.net.www.protocol.http.HttpURLConnection
,开启okhttp
feign.httpclient.enable=false
feign.okhttp.enable=true
OpenFeign默认超时时间为1s,超过1s就会返回错误页面。如果我们的接口处理业务确实超过1s,就需要对接口进行超时配置,如下:
ribbon: #设置feign客户端连接所用的超时时间,适用于网络状况正常情况下,两端连接所用时间
ReadTimeout: 1000 #指的是建立连接所用时间
ConnectTimeout: 1000 #指建立连接后从服务读取到可用资源所用时间
Feign 的工作流程:
@EnableFeignClient
这一注解的处理逻辑触发程序扫描 classPath中所有被@FeignClient
注解的类, 这里以 DemoService
为例, 将这些类解析为 BeanDefinition 注册到 Spring 容器中DemoService
时, Spring 会尝试从容器中查找 DemoService 的实现类DemoService
的实现类, 上面步骤获取到的 DemoService 的实现类必然是 feign 框架通过扩展 spring 的 Bean 处理逻辑, 为 DemoService
创建一个动态接口代理对象, 这里我们将其称为 DemoServiceProxy
注册到spring 容器中。DemoService
的 Bean 中注入了 DemoServiceProxy
这一实例。DemoService
的调用被统一转发到了由 Feign 框架实现的 InvocationHandler
中, InvocationHandler
负责将接口中的入参转换为 HTTP 的形式, 发到服务端, 最后再解析 HTTP 响应, 将结果转换为 Java 对象, 予以返回。Spring Cloud OpenFeign工作原理解析