Feign符合程序员对接口调用的习惯,内置了Ribbon。将Feign的注解绑定到接口之后就可以对注册中心中的服务进行调用! ## 一、OpenFeign是什么 [官方文档(opens new window)](https://cloud.spring.io/spring-cloud-static/Hoxton.SR1/reference/htmlsingle/#spring-cloud-openfeign) [Github地址(opens new window)](https://github.com/spring-cloud/spring-cloud-openfeign) > [Feign (opens new window)](https://github.com/OpenFeign/feign)is a declarative web service client. It makes writing web service clients easier. To use Feign create an interface and annotate it. It has pluggable annotation support including Feign annotations and JAX-RS annotations. Feign also supports pluggable encoders and decoders. Spring Cloud adds support for Spring MVC annotations and for using the same `HttpMessageConverters` used by default in Spring Web. Spring Cloud integrates Ribbon and Eureka, as well as Spring Cloud LoadBalancer to provide a load-balanced http client when using Feign. link > > 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的实现下,我们只需创建一个接口并使用注解的方式来配置它**(以前是Dao接口上面标注Mapper注解,现在是一个微服务接口上面标注一个Feign注解即可),即可完成对服务提供方的接口绑定,简化了使用Spring cloud Ribbon时,自动封装服务调用客户端的开发量。 **Feign集成了Ribbon** 利用Ribbon维护了Payment的服务列表信息,并且通过轮询实现了客户端的负载均衡。而与Ribbon不同的是,**通过feign只需要定义服务绑定接口且以声明式的方法**,优雅而简单的实现了服务调用。 **Feign和OpenFeign两者区别** **Feign**是Spring Cloud组件中的一个轻量级RESTful的HTTP服务客户端Feign内置了Ribbon,用来做客户端负载均衡,去调用服务注册中心的服务。Feign的使用方式是:使用Feign的注解定义接口,调用这个接口,就可以调用服务注册中心的服务。 ```xml org.springframework.cloud spring-cloud-starter-feign ``` OpenFeign是Spring Cloud在Feign的基础上支持了SpringMVC的注解,如@RequesMapping等等。OpenFeign的@Feignclient可以解析SpringMVC的@RequestMapping注解下的接口,并通过动态代理的方式产生实现类,实现类中做负载均衡并调用其他服务。 ```xml org.springframework.cloud spring-cloud-starter-openfeign ``` > feign 英 [feɪn] 美 [feɪn] v. 假装,装作,佯装(有某种感觉或生病、疲倦等) ## 二、OpenFeign服务调用 接口+注解:微服务调用接口 + @FeignClient 1、新建cloud-consumer-feign-order80 2、POM ```xml SpringCloudDemo com.xu.springcloud 1.0-SNAPSHOT 4.0.0 cloud-consumer-feign-order80 org.springframework.cloud spring-cloud-starter-openfeign org.springframework.cloud spring-cloud-starter-netflix-eureka-client com.xu.springcloud cloud-api-commons ${project.version} org.springframework.boot spring-boot-starter-web org.springframework.boot spring-boot-starter-actuator org.springframework.boot spring-boot-devtools runtime true org.projectlombok lombok true org.springframework.boot spring-boot-starter-test test ``` 3、YML ```yaml server: port: 80 eureka: client: register-with-eureka: false service-url: defaultZone: http://eureka7001.com:7001/eureka/,http://eureka7002.com:7002/eureka/ ``` 4、主启动 ```java @SpringBootApplication @EnableFeignClients public class OrderFeignMain80 { public static void main(String[] args) { SpringApplication.run(OrderFeignMain80.class,args); } } ``` 5、业务类 业务逻辑接口+@FeignClient配置调用provider服务 新建PaymentFeignService接口并新增注解@FeignClien ```java @Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService { @GetMapping(value = "/payment/get/{id}") public CommonResult getPaymentById(@PathVariable("id") Long id); } ``` 6、控制层Controller ```java @RestController @Slf4j public class OrderFeignController { @Resource private PaymentFeignService paymentFeignService; @GetMapping(value = "/consumer/payment/get/{id}") public CommonResult getPaymentById(@PathVariable("id") Long id){ return paymentFeignService.getPaymentById(id); } } ``` 7、测试 先启动2个eureka集群7001/7002 再启动2个微服务8001/8002 启动OpenFeign启动 - [http://localhost:80/consumer/payment/get/1(opens new window)](http://localhost:80/consumer/payment/get/1)  Feign自带负载均衡配置项 ## 三、OpenFeign超时控制 **超时设置,故意设置超时演示出错情况** 1、服务提供方8001/8002故意写暂停程序 ```java @RestController @Slf4j public class PaymentController { //... @Value("${server.port}") private String serverPort; //... @GetMapping(value = "/payment/feign/timeout") public String paymentFeignTimeout() { // 业务逻辑处理正确,但是需要耗费3秒钟 try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) { e.printStackTrace(); } return serverPort; } //... } ``` 2、服务消费方80添加超时方法PaymentFeignService ```java @Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE") public interface PaymentFeignService { //... @GetMapping(value = "/payment/feign/timeout") public String paymentFeignTimeout(); } ``` 3、服务消费方80添加超时方法OrderFeignController ```java @RestController @Slf4j public class OrderFeignController { @Resource private PaymentFeignService paymentFeignService; //... @GetMapping(value = "/consumer/payment/feign/timeout") public String paymentFeignTimeout(){ //openfeign-ribbon,客户端一般默认等待1秒钟 return paymentFeignService.paymentFeignTimeout(); } } ``` 4、测试 多次刷新+ [http://localhost:80/consumer/payment/feign/timeout(opens new window)](http://localhost:80/consumer/payment/feign/timeout) 将会跳出错误Spring Boot默认错误页面,主要异常:  **OpenFeign默认等待1秒钟,超过后报错** **YML文件里需要开启OpenFeign客户端超时控制** ```yaml #设置feign客户端超时时间(OpenFeign默认支持ribbon)(单位:毫秒) ribbon: #指的是建立连接所用的时间,适用于网络状况正常的情况下,两端连接所用的时间 ReadTimeout: 5000 #指的是建立连接后从服务器读取到可用资源所用的时间 ConnectTimeout: 5000 ``` - 重新访问  ## 四、OpenFeign日志增强 **日志打印功能** Feign提供了日志打印功能,我们可以通过配置来调整日恙级别,从而了解Feign 中 Http请求的细节。 说白了就是对Feign接口的调用情况进行监控和输出 **日志级别** - NONE:默认的,不显示任何日志; - BASIC:仅记录请求方法、URL、响应状态码及执行时间; - HEADERS:除了BASIC中定义的信息之外,还有请求和响应的头信息; - FULL:除了HEADERS中定义的信息之外,还有请求和响应的正文及元数据。 **配置日志bean** ```java import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } } ``` **YML文件里需要开启日志的Feign客户端** ```yaml logging: level: # feign日志以什么级别监控哪个接口 com.xu.springcloud.service.PaymentFeignService: debug ``` **后台日志查看** 再次访问[http://localhost:80/consumer/payment/get/23 (opens new window)](http://localhost:80/consumer/payment/get/23),得到更多日志信息。  最后修改:2023 年 05 月 22 日 © 允许规范转载 赞 2 如果觉得我的文章对你有用,请随意赞赏