OpenFeign
Feign是⼀个声明式WebService客户端。使⽤Feign能让编写Web Service客户端更加简单。它的使⽤⽅法是定义⼀个服务接⼝然后在上⾯添加注解。Feign也⽀持可拔插式的编码器和解码器。Spring Cloud对Feign进⾏了封装,使其⽀持了Spring MVC标准注解和HttpMessageConverters。Feign可以和Eureka和Ribbon组合使⽤以⽀持负载均衡。
Feign能做什么
Feign旨在使编写java Http客户端变得更容易。
前⾯使⽤了Ribbon+RestTemplate时,利⽤RestTemplate对http请求的封装处理,形成了⼀套模板化的调⽤⽅法。但是在实际开发中,由于对服务依赖的调⽤可能不⽌⼀处,往往⼀个接⼝会被多处调⽤,所以通常会针对每个微服务⾃⾏封装⼀些客户端类来包装这些依赖服务的调⽤。所以,Feign在此基础上做了进⼀步封装,由它来帮助我们定义和实现依赖服务接⼝的定义。在Feign的实现下,我们只需要创建⼀个接⼝并使⽤注解的⽅式来配置它(⼀个微服务接⼝上⾯标注⼀个Feign注解即可),即可完成对服务提供⽅的接⼝绑定,简化了使⽤Spring Cloud Ribbon时,⾃动封装服务调⽤客户端的开发量。
Feign集成了Ribbon
利⽤Ribbon维护了服务列表信息,并且通过轮询实现了客户端的负载均衡。⽽与Ribbon不同的是,通过feign只需要定义服务绑定接⼝且以声明式的⽅法,优雅⽽简单的实现服务调⽤。
Feign和OpenFeign的区别
OpenFeign使⽤
1,新建Module
2,POM⽂件
<dependencies>
<dependency>
<groupId>company.springcloud2020</groupId>
<artifactId>cloud-api-commons</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
</dependency>
</dependencies>
3,YML⽂件
server:
port: 84
spring:
application:
name: cloud-consumer-service
eureka:
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: eureka7001:7001/eureka,eureka7002:7002/eureka
instance:
instance-id: order84
prefer-ip-address: true
3,主启动类
@SpringBootApplication
@EnableFeignClients
public class OpenFeignOrder84 {
public static void main(String[] args) {
SpringApplication.run(OpenFeignOrder84.class,args);
}
}
4,业务类
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentService {
@GetMapping("/payment/{id}")
@ResponseBody
CommonRestult getPayment(@PathVariable("id") Integer id);
@PostMapping("/payment")
@ResponseBody
public CommonRestult savePayment(@RequestBody Payment payment);
}
@RestController
public class OrderController {
@Autowired
private PaymentService paymentService;
@PostMapping(value = "/consumer/openfeign/payment")
public CommonRestult savePayment(@RequestBody Payment payment){
CommonRestult commonRestult = paymentService.savePayment(payment);
return commonRestult;
}
@GetMapping("/consumer/openfeign/payment/{id}")
public CommonRestult getPaymentById(@PathVariable("id") Integer id){
CommonRestult payment = Payment(id);
return payment;
}
}
Feign⾃带负载均衡配置项
OpenFeign超时控制
1,在⽀付模块8001和⽀付模块8002的控制层添加⽅法(PaymentController.java)    @GetMapping("/payment/timeout")
public String pyamentFeignTimeout(){
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
return serverPort;
}
2,在当前订单模块中,添加⽅法
PaymentService.java
@Component
@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
public interface PaymentService {
@GetMapping("/payment/{id}")
@ResponseBody
CommonRestult getPayment(@PathVariable("id") Integer id);
@PostMapping("/payment")
@ResponseBody
CommonRestult savePayment(@RequestBody Payment payment);
@GetMapping("/payment/timeout")
String pyamentFeignTimeout();
}
OrderController.java
@RestController
public class OrderController {
@Autowired
private PaymentService paymentService;
@PostMapping(value = "/consumer/openfeign/payment")
public CommonRestult savePayment(@RequestBody Payment payment){
CommonRestult commonRestult = paymentService.savePayment(payment);
return commonRestult;
}
@GetMapping("/consumer/openfeign/payment/{id}")
public CommonRestult getPaymentById(@PathVariable("id") Integer id){
CommonRestult payment = Payment(id);
return payment;
}
@GetMapping("/consumer/payment/feign/timeout")
public String pyamentFeignTimeout(){
return paymentService.pyamentFeignTimeout();
}
}
默认Feign客户端只等待1秒钟,但是服务端处理需要超过1秒钟,导致客户端等待超时,直接报错。为了避免这种情况,有时候需要设置Feign客户端的超时控制(yml⽂件中开启配置)。
OpenFeign默认⽀持Ribbon,所以通过ribbon属性值控制,YML⽂件⾥需要开启OpenFeign客户端超时控制。
server:
port: 84
spring:
application:
name: cloud-consumer-service
eureka:
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: eureka7001:7001/eureka,eureka7002:7002/eureka
instance:
instance-id: order84
prefer-ip-address: true
ribbon:
#指的是建⽴连接后从服务器读取到可⽤资源所⽤的时间
ReadTimeout: 5000  #单位为毫秒
#指的是建⽴连接所⽤的时间,适⽤于⽹络正常的情况下,两端连接所⽤的时间
ConnectTimeOut: 5000  #单位为毫秒
OpenFeign进⾏⽇志打印
Feign提供了⽇志打印功能,可以通过配置来调整⽇志级别,从⽽了解Feign中Http请求的细节。也就是对Feign的接⼝调⽤情况进⾏监控和输出。
⽇志级别:
NONE:默认的,不显⽰任何⽇志。
BASIC:仅记录请求⽅法,URL,响应状态码及执⾏时间。
HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息。
FULL:除了HEADERS中定义的信息之外,还有请求和响应的正⽂和元数据。
1,添加⼀个配置⽂件,配置⽇志bean
@Configuration
public class FeignConfig {
@Bean
public Logger.Level feignLoggerLevel(){
return Logger.Level.FULL;
}
}
或者在YML⽂件中配置
feign:
client:
config:
default:
loggerLevel: FULL
#针对某个级别设置输出级别(设置局部的优先级别是最⾼的)
Book-service:
loggerLevel: FULL
2,YML⽂件⾥需要开启⽇志的Feign客户端
server:
port: 84
spring:
application:
name: cloud-consumer-service
eureka:
client:
fetch-registry: true
register-with-eureka: true
service-url:
defaultZone: eureka7001:7001/eureka,eureka7002:7002/eureka
instance:
instance-id: order84
prefer-ip-address: true
ribbon:
#指的是建⽴连接后从服务器读取到可⽤资源所⽤的时间
ReadTimeout: 5000  #单位为毫秒
#指的是建⽴连接所⽤的时间,适⽤于⽹络正常的情况下,两端连接所⽤的时间
ConnectTimeOut: 5000  #单位为毫秒
logging:springcloud和springboot
level:
#feign⽇志以什么级别控制哪个接⼝
company.service.PaymentService: debug
后台⽇志打印
总结
Spring Cloud OpenFeign的核⼼⼯作原理:
1. 通过@EnableFeignClients触发Spring应⽤程序对classpath中@FeignClient修饰类的扫描。
2. 解析到@FeignClient修饰类后,Feign框架通过扩展Spring Bean Definition的注册逻辑,最终注册⼀个FeignClientFactoryBean进⼊
Spring容器。
3. Spring容器在初始化其他⽤到@FeignClient接⼝的类时,获得的是FeignClientFactoryBean产⽣的⼀个代理对象Proxy。
4. 基于java原⽣的动态代理机制,针对Proxy的调⽤,都会被统⼀转发给Feign框架所定义的⼀个Invocati
onHandler,由该Handler完成后
续的HTTP转换,发送,接收,翻译HTTP响应的⼯作。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。