在前面的學習中,使用了Ribbon的負載均衡功能,大大簡化了遠端呼叫時的程式碼: 如果就學到這裡,你可能以後需要編寫類似的大量重複程式碼,格式基本相同,無非引數不一樣。有沒有更優雅的方 式,來對這些程式碼再次最佳化呢? 這就是接下來要學的Feign的功能了。
一、簡介 Feign也叫偽裝: Feign可以把Rest的請求進行隱藏,偽裝成類似SpringMVC的Controller一樣。你不用再自己拼接url,拼接引數等等 操作,一切都交給Feign去做。 專案主頁:https://github.com/OpenFeign/feign
1.2. 快速入門 1.2.1. 匯入依賴 在 consumer-demo 專案的 pom.xml 檔案中新增如下依賴
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>
1.2.2. Feign的客戶端
在 consumer-demo 中編寫如下Feign客戶端介面類:
package com.itheima.consumer.client; import com.itheima.consumer.pojo.User; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @FeignClient("user-service") public interface UserClient { @GetMapping("/user/{id}") User queryById(@PathVariable("id") Long id); }
首先這是一個介面,Feign會透過動態代理,幫我們生成實現類。這點跟mybatis的mapper很像 @FeignClient ,宣告這是一個Feign客戶端,同時透過 value 屬性指定服務名稱 介面中的定義方法,完全採用SpringMVC的註解,Feign會根據註解幫我們生成URL,並訪問獲取結果 @GetMapping中的/user,請不要忘記;因為Feign需要拼接可訪問的地址 編寫新的控制器類 ConsumerFeignController ,使用UserClient訪問:
package com.itheima.consumer.controller; import com.itheima.consumer.client.UserClient; import com.itheima.consumer.pojo.User; 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.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/cf") public class ConsumerFeignController { @Autowired private UserClient userClient; @GetMapping("/{id}") public User queryById(@PathVariable Long id){ return userClient.queryById(id); } }
1.2.3. 開啟Feign功能 在 ConsumerApplication 啟動類上,新增註解,開啟Feign功能
package com.itheima.consumer; import org.springframework.boot.SpringApplication; import org.springframework.cloud.client.SpringCloudApplication; import org.springframework.cloud.client.loadbalancer.LoadBalanced; import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.context.annotation.Bean; import org.springframework.web.client.RestTemplate; /*@SpringBootApplication @EnableDiscoveryClient @EnableCircuitBreaker*/ @SpringCloudApplication @EnableFeignClients//開啟Feign功能 public class ConsumerApplication { public static void main(String[] args) { SpringApplication.run(ConsumerApplication.class, args); } @Bean @LoadBalanced public RestTemplate restTemplate(){ return new RestTemplate(); } }
Feign中已經自動整合了Ribbon負載均衡,因此不需要自己定義RestTemplate進行負載均衡的配置。
1.2.4. 啟動測試 訪問介面:http://localhost:8080/cf/2
正常獲取到了結果。
1.3. 負載均衡 Feign中本身已經整合了Ribbon依賴和自動配置:
因此不需要額外引入依賴,也不需要再註冊 RestTemplate 物件。Fegin內建的ribbon預設設定了請求超時時長,預設是1000,我們可以透過手動配置來修改這個超時時長:
ribbon: ReadTimeout: 2000 # 讀取超時時長 ConnectTimeout: 1000 # 建立連結的超時時長
因為ribbon內部有重試機制,一旦超時,會自動重新發起請求。如果不希望重試,可以新增配置: 修改 consumer-demo\src\main\resources\application.yml 新增如下配置:
ribbon: ConnectTimeout: 1000 # 連線超時時長 ReadTimeout: 2000 # 資料通訊超時時長 MaxAutoRetries: 0 # 當前伺服器的重試次數 MaxAutoRetriesNextServer: 0 # 重試多少次服務 OkToRetryOnAllOperations: false # 是否對所有的請求方式都重試
重新給UserService的方法設定上執行緒沉睡時間2秒可以測試上述配置
1.4. Hystrix支援(瞭解) Feign預設也有對Hystrix的整合:
只不過,預設情況下是關閉的。需要透過下面的引數來開啟; 修改 consumer-demo\src\main\resources\application.yml 新增如下配置:
feign: hystrix: enabled: true # 開啟Feign的熔斷功能
但是,Feign中的Fallback配置不像Ribbon中那樣簡單了。 1)首先,要定義一個類,實現剛才編寫的UserFeignClient,作為fallback的處理類
package com.itheima.consumer.client.fallback; import com.itheima.consumer.client.UserClient; import com.itheima.consumer.pojo.User; import org.springframework.stereotype.Component; @Component public class UserClientFallback implements UserClient { @Override public User queryById(Long id) { User user = new User(); user.setId(id); user.setName("使用者異常"); return user; } }
2)然後在UserFeignClient中,指定剛才編寫的實現類
@FeignClient(value = "user-service", fallback = UserClientFallback.class) public interface UserClient { @GetMapping("/user/{id}") User queryById(@PathVariable("id") Long id); }
3)重啟測試 重啟啟動 consumer-demo 並關閉 user-service 服務,然後在頁面訪問:http://localhost:8080/cf/8
1.5. 請求壓縮(瞭解) Spring Cloud Feign 支援對請求和響應進行GZIP壓縮,以減少通訊過程中的效能損耗。透過下面的引數即可開啟請求 與響應的壓縮功能:
feign: compression: request: enabled: true # 開啟請求壓縮 response: enabled: true # 開啟響應壓縮
同時,我們也可以對請求的資料型別,以及觸發壓縮的大小下限進行設定:
feign: compression: request: enabled: true # 開啟請求壓縮 mime-types: text/html,application/xml,application/json # 設定壓縮的資料型別 min-request-size: 2048 # 設定觸發壓縮的大小下限
注:上面的資料型別、壓縮大小下限均為預設值。
1.6. 日誌級別(瞭解) 前面講過,透過 logging.level.xx=debug 來設定日誌級別。然而這個對Fegin客戶端而言不會產生效果。因為 @FeignClient 註解修改的客戶端在被代理時,都會建立一個新的Fegin.Logger例項。我們需要額外指定這個日誌的 級別才可以。 1)在 consumer-demo 的配置檔案中設定com.itheima包下的日誌級別都為 debug 修改 consumer-demo\src\main\resources\application.yml 新增如下配置:
logging:
level:
com.itheima: debug
2)在 consumer-demo 編寫FeignConfig配置類,定義日誌級別
package com.itheima.consumer.config; 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; } }
這裡指定的Level級別是FULL,Feign支援4種級別: NONE:不記錄任何日誌資訊,這是預設值。 BASIC:僅記錄請求的方法,URL以及響應狀態碼和執行時間 HEADERS:在BASIC的基礎上,額外記錄了請求和響應的頭資訊 FULL:記錄所有請求和響應的明細,包括頭資訊、請求體、後設資料。
3)在 consumer-demo 的 UserClient 介面類上的@FeignClient註解中指定配置類:
package com.itheima.consumer.client; import com.itheima.consumer.client.fallback.UserClientFallback; import com.itheima.consumer.config.FeignConfig; import com.itheima.consumer.pojo.User; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; @FeignClient(value = "user-service", fallback = UserClientFallback.class, configuration = FeignConfig.class) public interface UserClient { @GetMapping("/user/{id}") User queryById(@PathVariable Long id); }
4)重啟專案,訪問:http://localhost:8080/cf/8 ;即可看到每次訪問的日誌: