一,了解Feign
1,什麼是Feign
Netflix Feign
Feign是Netflix開發的聲明式、模闆化的HTTP用戶端, Feign可以幫助我們更快捷、優雅地調用HTTP API。
Feign實際上是對普通HTTP用戶端的一層封裝,其目的是降低內建成本、提升可靠性。Feign支援三種HTTP用戶端,包括JDK自帶的HttpURLConnection、Apache HttpClient和Square OkHttp,預設使用Apache HttpClient。
Spring Cloud Feign
Spring Cloud Feign是基于Netflix Feign實作,對Netflix Feign進行了增強,使Feign支援了Spring MVC注解,整合了Spring Cloud Ribbon和Spring Cloud Hystrix 提供負載均衡和斷路器。
2,Feign和Open Feign
其實Feign和Open Feign他倆是屬于同一個東西,Feign
僅僅隻是改名成為了
Open Feign而已,然後Open Feign項目在其基礎上繼續發展至今。
spring-cloud-starter-feign 從
1.2.0.RELEASE
開始 已放棄Netflix Feign而全面使用更新的Open Feign版本,
spring-cloud-starter-openfeign更是和Netflix Feign已經沒有關系了。
二,Feign的使用
1,服務消費方使用
1.1,起一個eureka服務:
1.2,向eureka-server中注冊一個服務提供者eureka-provider
application.yaml
spring:
application:
name: eureka-provider
eureka:
client:
service-url:
defaultZone: http://euk-server1:7001/eureka/
instance:
hostname: euk-client1
HelloController.java
@RestController
public class HelloController {
@Value("${server.port}")
private String port;
@GetMapping("/testFeign")
public String testFeign() {
System.out.println("port:" + port);
return "服務提供者,端口為:" + port;
}
}
1.3,使用Feign向eureka-server注冊服務消費者
導入Open Feign
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
配置appliation.yml 注冊到Eureka Server。
eureka:
instance:
hostname: localhost
client:
service-url:
defaultZone: http://euk-server1:7001/eureka/
spring:
application:
name: eureka-consumer
server:
port: 7008
使用@FeignClient為本應用聲明一個簡單的能調用的用戶端,value是需要調用的服務名。
@FeignClient(value = "eureka-provider")
public interface FeignInterface {
@RequestMapping("/testFeign")
public String testFeign();
}
接收外部請求,通過Feign遠端調用服務
@RestController
public class FeignController {
@Autowired
private FeignInterface feignInterface;
@RequestMapping("/testFeign")
public String testFeign() {
return feignInterface.testFeign();
}
}
在啟動類上添加 @EnableFeignClients 啟用 Feign
@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients
public class EurekaConsumer1Application {
public static void main(String[] args) {
SpringApplication.run(EurekaConsumer1Application.class, args);
}
}
啟動eureka-consumer然後通路http://localhost:7008/testFeign 傳回結果:
2,Fegin的繼承特性使用
Spring Cloud Feign提供了繼承特性,所謂的繼承特性就是将一些公共操作提取到一個父接口中,進而繼承父接口中的操作,減少代碼的重複開發,節約開發成本。
- 編寫通用服務接口A,接口方法上寫@RequestMapping(),此接口用于 feign。
- 服務提供者 實作上面接口A。
- 服務消費者的feign client接口 繼承A。
優點:
可以将接口的定義從 Controller 中剝離,同時配合 Maven 私有倉庫就可以輕易地實作接口定義的共享,不用再複制粘貼接口進行綁定,而是實作在建構期的接口綁定,進而有效減少服務用戶端的綁定配置。
缺點:
由于接口在建構期間就建立起了依賴,那麼接口變動就會對項目建構造成影響,可能服務提供方修改了一個接口定義,那麼會直接導緻用戶端工程的建構失敗。
2.1:首先我們建立一個通用model,eureka-feign-api
由于我們要用到spring mvc,是以pom.xml中要依賴spring web子產品
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
建立通用接口HelloInterface.java,用于eureka-provider實作,eureka-consumer繼承:
@RequestMapping("/feign")
@RestController
public interface HelloInterface {
@GetMapping("/hello")
String hello();
}
2.2:eureka-provider依賴eureka-feign-api并實作其通用接口HelloInterface
eureka-provider的pom添加依賴eureka-feign-api
<dependency>
<groupId>com.bobo</groupId>
<artifactId>eureka-feign-api</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
eureka-provider的controller實作通用接口HelloInterface
@RestController
public class FeignCommonProviderController implements HelloInterface {
@Value("${server.port}")
private int port;
@Override
public String hello() {
return "服務提供者,我的端口為:" + port;
}
}
eureka-provider啟動類
@SpringBootApplication
@EnableEurekaClient
public class EurekaProviderApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaProviderApplication.class, args);
}
}
3.3:eureka-consumer依賴eureka-feign-api并繼承其通用接口HelloInterface
eureka-consumer的pom依賴添加eureka-feign-api
<dependency>
<groupId>com.bobo</groupId>
<artifactId>eureka-feign-api</artifactId>
<version>0.0.1-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>
eureka-consumer繼承通用接口HelloInterface
@FeignClient("eureka-provider")
public interface FeignCommonInterface extends HelloInterface {
}
eureka-consumer通過FeignCommonInterface來實作Feign的調用
@RestController
public class FeignCommonController {
@Autowired
private FeignCommonInterface commonInterface;
@GetMapping("/hello")
public String hello(){
return commonInterface.hello();
}
}
eureka-consumer啟動類
@SpringBootApplication
@EnableEurekaClient
@EnableFeignClients
public class EurekaConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaConsumerApplication.class, args);
}
}
然後啟動eureka-server,eureka-provider,eureka-consumer,通過服務調用eureka-consumer
http://euk-client2:7008/hello 輸出:
三,Feign配置
feign的預設配置類是:org.springframework.cloud.openfeign.FeignClientsConfiguration。預設定義了feign使用的編碼器,解碼器等。
Feign允許自定義配置,自定義配置有如下兩種方式:
- 一種是Java 代碼配置,需要在@FeignClient(name = “eureka-consumer”,configuration = FeignAuthConfiguration.class)來引用配置。
- 第二種是直接配置檔案配置,在application.yml或者application.properties中配置。
1,Java代碼配置
public class FeignAutoConfiguration {
@Bean
public BasicAuthRequestInterceptor basicAuthRequestInterceptor() {
return new BasicAuthRequestInterceptor("root", "root");
}
}
@FeignClient(value = "eureka-provider",configuration = FeignAutoConfiguration.class)
public interface FeignCommonInterface extends HelloInterface {
}
如果在配置類上添加了@Configuration注解,并且該類在@ComponentScan所掃描的包中,那麼該類中的配置資訊就會被所有的@FeignClient共享。
最佳實踐是:不指定@Configuration注解,而是手動:@FeignClient(name = “eureka-provider”,configuration = FeignAuthConfiguration.class)
2,配置檔案配置
自定義攔截器:
/**
* @author bobo
* @date 2020-12-08
* 自定義攔截器
*/
public class MyBasicAuthRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
requestTemplate.header("Authorization", "Basic cm9vdDpyb290");
}
}
application.yaml
spring:
application:
name: eureka-consumer
eureka:
client:
service-url:
defaultZone: http://euk-server1:7001/eureka/
instance:
hostname: euk-client2
server:
port: 7008
feign:
client:
config:
eureka-peovider:
request-interceptors:
com.bobo.eurekaconsumer.MyBasicAuthRequestInterceptor
3,擴充
自定服務名稱配置:
feign:
client:
config:
service-valuation:
connect-timeout: 5000
read-timeout: 5000
logger-level: full
通用配置:
feign:
client:
config:
default:
connect-timeout: 5000
read-timeout: 5000
logger-level: full
4,Feign壓縮
Spring Cloud Feign 支援請求和響應進行GZIP壓縮來提高通信效率,但是會增加CPU壓力,建議把最小壓縮的文檔大小适度調大一點,進行gzip壓縮。
# 開啟GZIP壓縮配置:
#請求GZIP壓縮
feign.compression.request.enable=true
#響應GIZP壓縮
feign.compression.response.enable=true
#壓縮支援的mime type
feign.compression.request.mime-types=text/xml,application/xml.application/json
feign.compression.request.min-request-size=1024
#壓縮資料大小的最小值
5,Feign日志
Feign 為每一個FeignClient都提供了feign.logger執行個體,可在配置中或者java代碼中開啟日志。
feign:
client:
config:
# 服務名稱
eureka-provider:
logger-level: basic
上面logger-level有4種日志類型:
- none:不記錄任何日志,預設值。
- basic:僅記錄請求方法,url,響應狀态碼,執行時間。
- headers:在basic基礎上,記錄header資訊。
- full:記錄請求和響應的header,body,中繼資料。
上面的logger-level隻對下面的 debug級别日志做出響應:
logging:
level:
com.bobo.eureka-consumer.ServiceForecast: debug
四,寫在最後
上述例子代碼已上傳碼雲:https://gitee.com/songbozhao/spring-cloud-feign-test