Feign:
Feign 是一個聲明式的WebService 客戶端。使用 Feign能讓編寫WebService 客戶端更加簡單。
它的使用方式是 定義一個服務接口然后在上面添加注解。Feign 也支持可插拔式的編碼器和解碼器。SpringCloud 對Feign進行了封裝,使其支持了SpringMVC標准注解和HttpMessageConverters。Feign 可以與Eureka 和 Ribbon 組合使用以支持負載均衡。
官方解釋:
1. Declarative REST Client: Feign
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
HttpMessageConvertersused 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.
Feign 旨在使編寫 java http 客戶端變得更容易。
前面使用 Ribbon + RestTemplate時,利用RestTemplate對http請求的封裝處理,形成了一套模板化的調用方法。但是在實際開發中,由於對服務依賴的調用可能不止一處,往往一個接口會被多處調用,所以通常都會針對每個微服務自行封裝一些客戶端類來包裝這些依賴服務的調用。所以,Feign在此基礎上做了進一步封裝,由他來幫助我們定義和實現依賴服務接口的定義。在Feign的實現下,我們只需創建一個接口並使用注解的方式來配置它(以前是Dao接口上標注Mapper注解,現在是一個微服務接口上標注一個Feign注解即可),即可完成對服務提供方的接口綁定,簡化了使用SpringCloud Ribbon時,自動封裝調用客戶端的開發量。
Feign 集成了 Ribbon
利用Ribbon維護了各個服務提供者的服務列表信息,並且通過默認或用戶自定義的規則實現了客戶端的負載均衡。與Ribbon不同的是,通過Feign只需要定義服務綁定接口且以聲明式的方法,優雅而簡單的實現了服務調用。
Feign 和 OpenFeign 的區別:

OpenFeign 的使用:
1. 創建一個Module:cloud-consumer-feign-order8080
2. 引入OpenFeign依賴(將之前的cloud-consumer-order8080中的依賴全部復制過來,添加下面的OpenFeign依賴):
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
<?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>yct-cloud-parent</artifactId> <groupId>com.yct.springcloud</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>cloud-consumer-feign-order8080</artifactId> <dependencies> <dependency> <groupId>com.yct.springcloud</groupId> <artifactId>cloud-base-api</artifactId> <version>1.0-SNAPSHOT</version> <scope>compile</scope> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-eureka-server --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId> <exclusions> <exclusion> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </exclusion> </exclusions> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-web --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <!-- https://mvnrepository.com/artifact/org.projectlombok/lombok --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-test --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> </project>
3. YML文件(將之前的cloud-consumer-order8080中的YML文件直接復制過來使用,可以修改一下服務名,也可以不修改):
server:
port: 8080
spring:
application:
name: cloud-feign-order-service
eureka:
client:
register-with-eureka: true
fetchRegistry: true
service-url:
defaultZone: http://eureka7001.com:7001/eureka,http://eureka7002.com:7002/eureka #集群版
# defaultZone: http://localhost:7001/eureka
instance:
instance-id: order8080
prefer-ip-address: true
4. 主啟動類(添加注解:@EnableFeignClients):
package com.yct.springcloud; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.eureka.EnableEurekaClient; import org.springframework.cloud.openfeign.EnableFeignClients; @EnableEurekaClient @SpringBootApplication @EnableFeignClients //開啟使用OpenFeign組件 public class CustomerFeignOrderApplication8080 { public static void main(String[] args) { SpringApplication.run(CustomerFeignOrderApplication8080.class,args); } }
5. 創建一個和服務提供者類似的接口 IPaymentService,並添加注解:@FeignClient(value = "CLOUD-PAYMENT-SERVICE")
package com.yct.springcloud.service; import com.yct.springcloud.support.CommonResult; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @Component @FeignClient(value = "CLOUD-PAYMENT-SERVICE") public interface IPaymentService { /** * 根據ID查詢支付數據 * * @param id * @return */ @GetMapping(value = "/yct/payment/get/{id}") public CommonResult getPaymentById(@PathVariable("id") Long id); }
6. 創建Controller,直接調用上面的接口的方法:
package com.yct.springcloud.controller; import com.yct.springcloud.entity.pay.Payment; import com.yct.springcloud.service.IPaymentService; import com.yct.springcloud.support.CommonResult; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RestController; /** * 訂單Controller */ @RestController @Slf4j public class OrderController { @Autowired IPaymentService iPaymentService; @GetMapping(value = "/consumer/payment/feign/getPayment/{id}") public CommonResult<Payment> getPayment(@PathVariable("id") Long id) { log.info("Consumer:根據id【" + id + "】查詢支付數據。"); return iPaymentService.getPaymentById(id); } }
啟動測試:


默認是輪詢的負載均衡策略(如果需要修改的話,方式和修改Ribbon的負載均衡策略是相同的,因為OpenFeign本身就集成了Ribbon)。
OpenFeign的超時控制:
默認情況下,Feign客戶端只等待一秒鍾,如果服務端處理超過了一秒鍾,則Feign客戶端就直接會報錯。
效果演示(在服務提供方,故意弄一個有延時的服務接口,比如,睡3秒鍾再返回):
1. 在服務提供者8001的Controller中,增加一個模仿延時的接口。

2. 消費者訪問這個接口(按照之前的訪問方式)。
3.只留8001一個服務提供者,然后再進行訪問,訪問結果:超時

為了避免Feign等待超時這種情況,我們需要設置Feign客戶端的超時控制:
yml 文件中開啟配置:
ribbon: ReadTimeout: 5000 ConnectTimeout: 5000
注意:IDEA會提示沒有這兩個屬性,不用管,弄上去就行。

再次測試,可以了:

OpenFeign的日志打印功能:
Feign提供了日志打印功能,我們可以通過配置來調整日志級別,從而了解Feign中Http請求的細節。
說白了就是對Feign接口的調用情況進行監控和輸出。
日志級別:

配置日志bean:
package com.yct.springcloud.config; import feign.Logger; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * Feign日志的Bean配置 */ @Configuration public class FeignConfig { @Bean Logger.Level feignLoggerLevel(){ return Logger.Level.FULL; } }

yml中開啟日志的Feign客戶端。
logging:
level:
com.yct.springcloud.service.IPaymentService: debug

測試結果:

