Feign簡介:
Feign是一個聲明式的Web服務客戶端,使用Feign可使得Web服務客戶端的寫入更加方便.它具有可插拔注釋支持,包括Feign注解和JAX-RS注解、Feign還支持可插拔編碼器和解碼器、Spring Cloud增加了對Spring MVC注釋的支持,並HttpMessageConverters在Spring Web中使用了默認使用的相同方式。Spring Cloud集成了Ribbon和Eureka,在使用Feign時提供負載平衡的http客戶端。Fegin對Robbin進行了封裝,如果需要配置自己的負載算法,可以自定義Ribbon的算法即可。 Spring Cloud Feign 提供的聲明式服務綁定功能來實現對該服務接口的調用。
1.創建 一 個 Spring Boot 基礎工程,對pom文件修改
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<spring-cloud.version>Finchley.SR3</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<!-- SpringCloud 所有子項目 版本集中管理. 統一所有SpringCloud依賴項目的版本依賴-->
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
<version>1.4.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin><!-- SpringBoot 項目打jar包的Maven插件 -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
2.application.yml
server: port: 9012 spring: application: name: feign-server #服務注冊到Eureka上使用的名稱 eureka: client: serviceUrl: defaultZone: http://localhost:7001/eureka/,http://localhost:7002/eureka/
instance: instance-id: feign-server-9012 prefer-ip-address: true #訪問路徑顯示IP地址
3.修改主啟動類
@SpringBootApplication @EnableDiscoveryClient @EnableFeignClients(basePackages = {"com.wuzz.demo"}) public class FeignApp { public static void main( String[] args ) { SpringApplication.run(FeignApp.class, args); } }
4.負載均衡配置
@Configuration public class ConfigBean { // Eureka是基於REST(Representational State Transfer)服務, // 主要以AWS雲服務為支撐,提供服務發現並實現負載均衡和故障轉移。 // 我們稱此服務為Eureka服務。 // Eureka提供了Java客戶端組件,Eureka Client,方便與服務端的交互。 // 客戶端內置了基於round-robin實現的簡單負載均衡。 // 在Netflix,為Eureka提供更為復雜的負載均衡方案進行封裝, // 以實現高可用,它包括基於流量、資源利用率以及請求返回狀態的加權負載均衡。
/** * Ribbon是Netflix發布的雲中間層服務開源項目,主要功能是提供客戶端負載均衡算法。 Ribbon客戶端組件提供一系列完善的配置項,如,連接超時,重試等。 簡單的說,Ribbon是一個客戶端負載均衡器, 我們可以在配置文件中列出load Balancer后面所有的機器, Ribbon會自動的幫助你基於某種規則(如簡單輪詢,隨機連接等)去連接這些機器, 我們也很容易使用Ribbon實現自定義的負載均衡算法 * */
// Feign是一個聲明式的Web服務客戶端,使用Feign可使得Web服務客戶端的寫入更加方便。 // 它具有可插拔注釋支持,包括Feign注解和JAX-RS注解、Feign還支持可插拔編碼器和解碼器、 // Spring Cloud增加了對Spring MVC注釋的支持, // 並HttpMessageConverters在Spring Web中使用了默認使用的相同方式。 // Spring Cloud集成了Ribbon和Eureka,在使用Feign時提供負載平衡的http客戶端。
@Bean @LoadBalanced // ribbon是客戶端 的負載均衡工具 //默認算法是輪詢算法 核心組件IRule
public RestTemplate getRestTemplate() { return new RestTemplate(); } @Bean public IRule myRule() { // 負載均衡算法。。。。 // return new RoundRobinRule();
return new RandomRule(); } }
5.聲明式服務類
@FeignClient(value ="cloud-provider") public interface ClientService { //如果feign代理的是get請求,必須用@RequestMapping 不能用@GetMapping // 每個參數必須帶上@RequestParam,否則會報post not support! @RequestMapping(value = "/hello", method = RequestMethod.GET) String hello(@RequestParam("id") String id) ;
}
6.controller
@RestController public class FeignController { @Autowired private ClientService service; @RequestMapping(value ="/feign/hello") public String hello() { return service.hello("1"); } }
這樣就配置好了。
指定服務配置:
大多數情況下,我們對於服務調用的超時時間可能會根據實際服務的特性做 一 些調整,所以僅僅依靠默認的全局配置是不行的。 在使用SpringCloud Feign的時候,針對各個服務客戶端進行個性化配置的方式與使用SpringCloud Ribbon時的配置方式是 一 樣的, 都采用<client>. ribbon.key=value 的格式進行 設置。在定義Feign客戶端的時候, 我們使用了@FeignClient注解。 在初始化過程中,SpringCloud Feign會根據該注解的name屬性或value屬性指定的服務名, 自動創建一 個同名的Ribbon客戶端。也就是說,在之前的示例中,使用@FeignClient(value= "cloud-provider")來創 建 Feign 客 戶 端 的 時 候 , 同時也創建了一個 名為cloud-provider的Ribbon客戶端。 既然如此, 我們就可以使用@FeignClient注解中的name或value屬性值來設置對應的Ribbon參數, 比如:
cloud-provider.ribbon.ConnectTimeout = 500 //請求連接的超時時間。
cloud-provider.ribbon.ReadTimeout = 2000 //請求處理的超時時間。
cloud-provider.ribbon.OkToRetryOnAllOperations = true //對所有操作請求都進行重試。
cloud-provider.ribbon.MaxAutoRetriesNextServer = 2 //切換實例的重試次數。
cloud-provider.ribbon.MaxAutoRetries = 1 //對當前實例的重試次數。
重試機制:
在 Spring Cloud Feign 中默認實 現了 請 求 的重 試 機 制 , 而上面我 們對 於 cloud-provider 客戶端的配置內容就是對於請求超時以及重試機制配置的詳情.
這里需要注意一 點, Ribbon的超時 與Hystrix的超時是兩個概念。 為了讓上述實現有效,我們需要 讓Hystrix的超時時間大於Ribbon的超時時間, 否則Hystrix命令超時后, 該命令直接熔斷, 重試機制就 沒有任何意義了。
要么設置 Hystrix 的超時時間比Ribbon大(hystrix.command.default.execution.isolation.thread. timeoutInMilliseconds = 5000),要么直接關閉 Hystrix 超時配置(feign.hystrix.enabled= false).配置的時候不提示沒關系,配置上就有效果。
如果不想全局關閉可以只針對服務進行關閉:@FeignClient(name="HELLO - SERVICE", configuration = DisableHystrixConfiguration.class)
在 feign-server應用中增加上文中提到的重試配置參數。其中,由於 cloud-provider.ribbon.MaxAutoRetries 設置為 1, 所以重試策略先嘗試訪問首選實例 一 次, 失敗后才更換實例訪問, 而更換實例訪問的次數通過 cloud-provider.ribbon.MaxAutoRetriesNextServer 參數 設置為 2, 所以會嘗試更換兩次實例進行重試。
最后, 啟動這些應用, 並嘗試訪問幾次 http://localhost:9012/feign/hello 接口。可以通過 cloud-provider 服務打印請求信息,修改對應/hello接口如下
public String hello(String id) throws InterruptedException { // 測試fegin 超時重試代碼開始
List<ServiceInstance> instances = client.getInstances("feign-server"); //測試超時
int sleepTime = new Random().nextInt(3000); System.out.println("sleepTime:" + sleepTime); Thread.sleep(sleepTime); System.out.println("/hello, host:" + instances.get(0).getHost() + instances.get(0).getServiceId()); // 測試fegin 超時重試代碼結束
return "Hello Eureka Provider1"; }
然后控制台來查看重試的日志。
從控制台輸出中,我們可以看到這次訪問的第 一 次請求延遲時間為 2088毫秒,由於超時時間設置為 2000 毫秒, Feign 客戶端發起了重試,第二次請求的延遲為 1338 秒,沒有超時 。Feign客戶端在進行服務調用時, 雖然經歷了一 次失敗,但是通過重試機制, 最終還是獲得了請求結果。所以, 對於 重試機制的實現, 對於構建高可用的 服務集群來說非常重要, 而 SpringCloud Feign也為其提供了足夠的支持。
其他配置:
請求壓縮。Spring Cloud Feign支持對請求與響應進行 GZIP 壓縮,以減少通信過程中的性能損耗 。我們只需通過下面兩個參數設置, 就能開啟請求與響應的壓縮功能:
feign.compression.request.enabled = true feign.compression.response.enabled = true
同時, 我們還能對請求壓縮做 一 些更細致的設置, 比如下面的配置內容指定了壓縮的請求數據類型, 並設置了請求壓縮的大小下限, 只有超過這個大小的請求才會對其進行壓縮。
feign.compression.request.enabled = true feign.compression.request.mime-types = text/xml,application/xml,application/json //默認值 feign.compression.request.min-request-size=2048 //默認值
日志配置:
Spring Cloud Feign 在構建被 @FeignClient 注解修飾的服務客戶端時,會為每 一 個客戶端都創建 一 個 feign.Logger 實例,我們可以利用該日志對象的 DEBUG 模式來幫助分析 Feign 的請求細節。可以在 application.properties 文件中使用 logging.level.<FeignClient> 的參數配置格式來開啟指定 Feign 客戶端的 DEBUG 日志, 其中<FeignClient> 為 Feign 客戶端定義接口的完整路徑, 比如針對本文中我們實現的 HelloService 可以按如下配置開啟:
logging.level.com.wuzz.demo.HelloService = DEBUG
但是, 只是添加了如上配置, 還無法實現對 DEBUG 日志的輸出。 這時由於 Feign 客戶端默認的 Logger.Level 對象定義為 NONE 級別, 該級別不會記錄任何 Feign 調用過程中的信息, 所以我們需要調整它的級別, 針對全局的日志級別, 可以在應用主類中直接加入 Logger.Level 的 Bean 創建, 具體如下:
@Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; }
或者添加個配置類:
@Configuration public class FullLogConfiguration { @Bean Logger.Level feignLoggerLevel() { return Logger.Level.FULL; } @FeignClient(name = "cloud-provider", configuration = FullLogConfiguration.class) public interface HelloService { 。。。。。。 }
在調整日志級別為 FULL 之后, 我們可以再訪問一 下之前的http://localhost:9012/feign/hello 接口,這時我們在 feign-server的控制台中就可以看到對應的日志。類似如下信息:
對於 Feign 的 Logger 級別主要有下面 4 類, 可根據實際需要進行調整使用。
- NONE: 不記錄任何信息。
- BASIC: 僅記錄請求方法、URL以及響應狀態碼和執行時間。
- HEADERS: 除了記錄BASIC級別的信息之外, 還會記錄請求和響應的頭信息。
- FULL: 記錄所有請求與響應的明細, 包括頭信息、 請求體、 元數據等。
服務降級(Feign客戶端):
整體資源快不夠了,忍痛將某些服務先關掉,待渡過難關,再開起會來。所謂降級,一般是從整體負荷考慮,就是當某個服務熔斷后,服務器將不再被調用,此時客戶端可以准備自己本地的一個fallback回調,返回一個缺省值,這樣做,雖然服務水平下降,但好歹可用,比直接掛掉要強,服務降級是在客戶端進行的.
1. 根據目標接口,創建一個實現了FallbackFactory的類
@Component
public class HystrixClientService implements FallbackFactory<ClientService> {
@Override
public ClientService create(Throwable throwable) {
return new ClientService() {
@Override
public String hello() {
return "服務降級。。。。";
}
};
}
}
2. 在目標接口上的@FeignClient中添加fallbackFactory屬性值
@FeignClient(value ="cloud-provider", fallbackFactory = HystrixClientService.class)
public interface ClientService {
@RequestMapping(value ="/hello",method= RequestMethod.GET)
String hello() ;
}
3.修改 application.yml ,添加一下
feign:
hystrix:
enabled: true
這樣就完成了服務降級的基本配置,可以進入測試。。。。
Ribbon和 Feign的區別:
- Ribbon添加maven依賴 spring-starter-ribbon 使用@RibbonClient(value="服務名稱") 使用RestTemplate調用遠程服務對應的方法。feign添加maven依賴 spring-starter-feign 服務提供方提供對外接口 調用方使用 在接口上使用 @FeignClient("指定服務名")
- Ribbon和Feign都是用於調用其他服務的,不過方式不同。
- 啟動類使用的注解不同,Ribbon用的是@RibbonClient,Feign用的是@EnableFeignClients。
- 服務的指定位置不同,Ribbon是在@RibbonClient注解上聲明,Feign則是在定義抽象方法的接口中使用@FeignClient聲明。
- 調用方式不同,Ribbon需要自己構建http請求,模擬http請求然后使用RestTemplate發送給其他服務,步驟相當繁瑣。
- Feign則是在Ribbon的基礎上進行了一次改進,采用接口的方式,將需要調用的其他服務的方法定義成抽象方法即可,不需要自己構建http請求。不過要注意的是抽象方法的注解、方法簽名要和提供服務的方法完全一致。