Spring Cloud(Finchley.SR1)之feign(四)
1.Feign簡介
目錄
3. Feign的Encoder、Decoder和ErrorDecoder
Feign是一個宣告式的Web服務客戶端。這使得Web服務客戶端的寫入更加方便 要使用Feign建立一個介面並對其進行註釋。它具有可插入註釋支援,包括Feign註釋和JAX-RS註釋。Feign還支援可插拔編碼器和解碼器。Spring Cloud增加了對Spring MVC註釋的支援,並使用Spring Web中預設使用的HttpMessageConverters
。Spring Cloud整合Ribbon和Eureka以在使用Feign時提供負載均衡的http客戶端。
在Spring Cloud Netflix棧中,各個微服務都是以HTTP介面的形式暴露自身服務的,因此在呼叫遠端服務時就必須使用HTTP客戶端。我們可以使用JDK原生的URLConnection
、Apache的Http Client
、Netty的非同步HTTP Client, Spring的RestTemplate
。但是,用起來最方便、最優雅的還是要屬Feign了。
Feign是一種宣告式、模板化的HTTP客戶端。在Spring Cloud中使用Feign, 我們可以做到使用HTTP請求遠端服務時能與呼叫本地方法一樣的編碼體驗,開發者完全感知不到這是遠端方法,更感知不到這是個HTTP請求。
現在為止所進行的 有Rest 服務呼叫實際上都會出現一個非常尷尬的局面,所有的資料呼叫和轉換都必須由戶自己來完成,而我們本身不擅 所有的資料呼叫和轉換都必須由戶自己來完成,我們習慣的程式設計模式是:通過介面來實現業務 長這些,我們習慣的程式設計模式是:通過介面來實現業務 ,這可以通過feign來實現,Feign = RestTempate + HttpHeader Ribbon Eureka綜合體 綜合體 = 業務介面的自動例項化。
2.使用Feign
2.1 pom.xml中新增
老版本用spring-cloud-starter-feign,Finchley.SR1版本的用spring-cloud-starter-openfeign
<?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>spring-cloud</artifactId>
<groupId>com.alen</groupId>
<version>0.0.1-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging>
<artifactId>feign-service</artifactId>
<dependencies>
<!--eureka client -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<!--feign支援-->
<!--feign支援-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.2 定義介面
為了讓Feign知道在呼叫方法時應該向哪個地址發請求以及請求需要帶哪些引數,我們需要定義一個介面:
package com.alen.service;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
/**
* 定義一個feign介面,通過@ FeignClient(“服務名”),來指定呼叫哪個服務
**/
@FeignClient(value ="eureka-client")
public interface HelloService {
@RequestMapping("/hello")
//必須顯示的指定age,不顯示還不行
String hello(@RequestParam("age") Integer age);
}
A: @FeignClient
用於通知Feign元件對該介面進行代理(不需要編寫介面實現),使用者可直接通過@Autowired
注入。
B: @RequestMapping
表示在呼叫該方法時需要向/group/{groupId}
傳送GET
請求。
C: @PathVariable
與SpringMVC
中對應註解含義相同。
Spring Cloud應用在啟動時,Feign會掃描標有@FeignClient
註解的介面,生成代理,並註冊到Spring容器中。生成代理時Feign會為每個介面方法建立一個RequetTemplate
物件,該物件封裝了HTTP請求需要的全部資訊,請求引數名、請求方法等資訊都是在這個過程中確定的,Feign的模板化就體現在這裡。
在本例中,我們將Feign與Eureka和Ribbon組合使用,@FeignClient(name = "ea")
意為通知Feign在呼叫該介面方法時要向Eureka中查詢名為ea
的服務,從而得到服務URL。
controller中呼叫這個介面
@RestController
public class HelloController {
@Autowired
private HelloService helloService;
/**
* 通過Controller呼叫遠端服務
* @param age
* @return
*/
@RequestMapping("/hello")
public String home(@RequestParam Integer age) {
return helloService.hello(age);
}
}
2.3 啟動類
@SpringBootApplication
//通過註解@EnableEurekaClient 表明自己是一個eurekaclient.
@EnableEurekaClient
//開啟Feign的功能
@EnableFeignClients
public class App {
public static void main(String[] args) {
SpringApplication.run(App.class, args);
}
}
2.4 application.yml檔案
server:
port: 8014
eureka:
instance:
hostname: localhost
# 發呆時間,即服務失效時間(預設為90s),就是超過15秒沒有續約就會從登錄檔中剔除
lease-expiration-duration-in-seconds: 15
# 心跳時間,即服務續約間隔時間(預設為30s)
lease-renewal-interval-in-seconds: 5
client:
#設定eureka伺服器所在的地址,查詢服務和註冊服務都需要依賴這個地址。高可用的註冊中心時,
#可以配置多個註冊中心,通過逗號隔開
service-url:
defaultZone: http://localhost:8010/eureka/
Feign的原始碼實現的過程如下:
- 首先通過@EnableFeignCleints註解開啟FeignCleint
- 根據Feign的規則實現介面,並加@FeignCleint註解
- 程式啟動後,會進行包掃描,掃描所有的@ FeignCleint的註解的類,並將這些資訊注入到ioc容器中。
- 當介面的方法被呼叫,通過jdk的代理,來生成具體的RequesTemplate
- RequesTemplate在生成Request
- Request交給Client去處理,其中Client可以是HttpUrlConnection、HttpClient也可以是Okhttp
- 最後Client被封裝到LoadBalanceClient類,這個類結合類Ribbon做到了負載均衡。
2.5 覆蓋Feign預設值,自定義FeignClient
預設的配置類為FeignClientsConfiguration,這個類在spring-cloud-netflix-core的jar包下,開啟這個類,可以發現它是一個配置類,注入了很多的相關配置的bean,包括feignRetryer、FeignLoggerFactory、FormattingConversionService等,其中還包括了Decoder、Encoder、Contract,如果這三個bean在沒有注入的情況下,會自動注入預設的配置。
- Decoder feignDecoder: ResponseEntityDecoder(這是對SpringDecoder的封裝)
- Encoder feignEncoder: SpringEncoder
- Logger feignLogger: Slf4jLogger
- Contract feignContract: SpringMvcContract
- Feign.Builder feignBuilder: HystrixFeign.Builder
@Configuration
public class FeignClientsConfiguration {
...//省略程式碼
@Bean
@ConditionalOnMissingBean
public Decoder feignDecoder() {
return new ResponseEntityDecoder(new SpringDecoder(this.messageConverters));
}
@Bean
@ConditionalOnMissingBean
public Encoder feignEncoder() {
return new SpringEncoder(this.messageConverters);
}
@Bean
@ConditionalOnMissingBean
public Contract feignContract(ConversionService feignConversionService) {
return new SpringMvcContract(this.parameterProcessors, feignConversionService);
}
...//省略程式碼
}
重寫配置:
你可以重寫FeignClientsConfiguration中的bean,從而達到自定義配置的目的,比如FeignClientsConfiguration的預設重試次數為Retryer.NEVER_RETRY,即不重試,那麼希望做到重寫,寫個配置檔案,注入feignRetryer的bean,程式碼如下:
@Configuration
public class FeignClientConfig{
@Bean
public Retryer feignRetryer() {
return new Retryer.Default(100, SECONDS.toMillis(1), 5);
}
}
在上述程式碼更改了該FeignClient的重試次數,重試間隔為100ms,最大重試時間為1s,重試次數為5次。
在這種情況下,客戶端由FeignClientsConfiguration中的元件與FeignClientConfig中的任何元件組成(後者將覆蓋前者)。
需要注意的是: FeignClientConfig類不能包含在主應用程式上下文的@ComponentScan中,否則該配置會被所有的@FeignClient共享。Ribbon的自定義配置中也需要注意這個問題。可以通過將其放置在任何@ComponentScan或@SpringBootApplication的單獨的不重疊的包中,或者可以在@ComponentScan中明確排除。
2.6 .Feign 相關配置
Feign之中最為核心的作用就是將 Rest 服務的資訊轉換為介面,但是在實際使用之中也需要 考慮到一些配置情況, 例如:資料壓縮,Rest 的核心本質在於: JSON 資料傳輸( XML、文字),於是就必須思考一種情況,玩意 、文字),使用者傳送的資料很大呢? 所以這個時候可考慮修改 application.yml 配置檔案對傳輸資料進行壓縮; 配置檔案對傳輸資料進行壓縮;
feign:
compression:
request:
mime-types: # 可以被壓縮的型別
# - text/xml
# - application/xml
# - application/json
min-request-size: 2048 # 超過2048的位元組進行壓縮
2、 如果有需要則可以在專案之中開啟 feign的相關日誌資訊(預設不開啟) :
為每個建立的Feign客戶端建立一個記錄器。預設情況下,記錄器的名稱是用於建立Feign客戶端的介面的完整類名。Feign日誌記錄僅響應DEBUG
級別
修改 application.yml配置檔案,追加日誌追蹤:
logging:
level:
# feign介面包所在位置
cn.mldn.service: DEBUG
修改 FeignClientConfig ,開啟日誌的輸出:
您可以為每個客戶端配置的Logger.Level
物件告訴Feign記錄多少。選擇是:
-
NONE
,無記錄(DEFAULT)。 -
BASIC
,只記錄請求方法和URL以及響應狀態程式碼和執行時間。 -
HEADERS
,記錄基本資訊以及請求和響應標頭。 -
FULL
,記錄請求和響應的標頭檔案,正文和後設資料。
例如,以下將Logger.Level
設定為FULL
:
@Configuration
public class FeignClientConfig {
@Bean
public Logger.Level getFeignLoggerLevel() {
return feign.Logger.Level.FULL ;
}
}
3. Feign的Encoder、Decoder和ErrorDecoder
Feign將方法簽名中方法引數物件序列化為請求引數放到HTTP請求中的過程,是由編碼器(Encoder)完成的。同理,將HTTP響應資料反序列化為java物件是由解碼器(Decoder)完成的。
預設情況下,Feign會將標有@RequestParam
註解的引數轉換成字串新增到URL中,將沒有註解的引數通過Jackson轉換成json放到請求體中。注意,如果在@RequetMapping
中的method
將請求方式指定為POST
,那麼所有未標註解的引數將會被忽略,例如:
@RequestMapping(value = "/group/{groupId}", method = RequestMethod.GET)
void update(@PathVariable("groupId") Integer groupId, @RequestParam("groupName") String groupName, DataObject obj);
此時因為宣告的是GET請求沒有請求體,所以obj
引數就會被忽略。
在Spring Cloud環境下,Feign的Encoder*只會用來編碼沒有新增註解的引數*。如果你自定義了Encoder, 那麼只有在編碼obj
引數時才會呼叫你的Encoder。對於Decoder, 預設會委託給SpringMVC中的MappingJackson2HttpMessageConverter
類進行解碼。只有當狀態碼不在200 ~ 300之間時ErrorDecoder才會被呼叫。ErrorDecoder的作用是可以根據HTTP響應資訊返回一個異常,該異常可以在呼叫Feign介面的地方被捕獲到。我們目前就通過ErrorDecoder來使Feign介面丟擲業務異常以供呼叫者處理。
Feign的HTTP Client
Feign在預設情況下使用的是JDK原生的URLConnection
傳送HTTP請求,沒有連線池,但是對每個地址會保持一個長連線,即利用HTTP的persistence connection
。我們可以用Apache的HTTP Client替換Feign原始的http client, 從而獲取連線池、超時時間等與效能息息相關的控制能力。Spring Cloud從Brixtion.SR5
版本開始支援這種替換,首先在專案中宣告Apache HTTP Client和feign-httpclient
依賴:
<!-- 使用Apache HttpClient替換Feign原生httpclient -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
</dependency>
<dependency>
<groupId>com.netflix.feign</groupId>
<artifactId>feign-httpclient</artifactId>
<version>${feign-httpclient}</version>
</dependency>
然後在application.properties
中新增:
feign.httpclient.enabled=true
總結
通過Feign, 我們能把HTTP遠端呼叫對開發者完全透明,得到與呼叫本地方法一致的編碼體驗。這一點與阿里Dubbo中暴露遠端服務的方式類似,區別在於Dubbo是基於私有二進位制協議,而Feign本質上還是個HTTP客戶端。如果是在用Spring Cloud Netflix搭建微服務,那麼Feign無疑是最佳選擇。
參考:
http://blog.csdn.net/neosmith/article/details/52449921
https://springcloud.cc/spring-cloud-dalston.html#spring-cloud-feign
相關文章
- Spring Cloud 之 Feign.SpringCloud
- Spring-Cloud之Feign原理剖析SpringCloud
- Spring Cloud Feign 應用SpringCloud
- Spring Cloud Feign設計原理SpringCloud
- Spring Cloud feign使用okhttp3SpringCloudHTTP
- Spring Cloud Feign 效能最佳化SpringCloud
- Spring Cloud中Feign配置詳解SpringCloud
- Spring Cloud應用(三)---feign使用SpringCloud
- Spring Cloud(四)服務提供者 Eureka + 服務消費者 FeignSpringCloud
- 微服務實戰SpringCloud之Spring Cloud Feign替代HTTP Client微服務SpringGCCloudHTTPclient
- Spring Cloud Feign 宣告式服務呼叫SpringCloud
- Spring Cloud Feign設計原理(轉載)SpringCloud
- 宣告式服務呼叫 Spring Cloud FeignSpringCloud
- Spring Cloud Feign 如何使用物件引數SpringCloud物件
- 微服務Spring Cloud17_Feign9微服務SpringCloud
- Spring Boot系列(四) Spring Cloud 之 Config ClientSpring BootCloudclient
- Spring Cloud Alibaba(8)---Feign服務呼叫SpringCloud
- Spring cloud(3)-負載均衡(Feign,Ribbon)SpringCloud負載
- Spring Cloud Feign 熔斷機制填坑SpringCloud
- Spring Cloud構建微服務架構(Feign)SpringCloud微服務架構
- Spring Cloud 專題之四:Zuul閘道器SpringCloudZuul
- Spring Cloud Feign的檔案上傳實現SpringCloud
- springcloud學習筆記(二)Spring Cloud FeignSpringGCCloud筆記
- Spring Cloud中,Feign常見問題總結SpringCloud
- spring cloud微服務快速教程之(十四)spring cloud feign使用okhttp3--以及feign呼叫引數丟失的說明SpringCloud微服務HTTP
- Bug集錦-Spring Cloud Feign呼叫其它介面報錯SpringCloud
- Spring Cloud微服務-基於Eureka的feign呼叫(1)SpringCloud微服務
- Spring Cloud:使用 Feign 實現負載均衡詳解SpringCloud負載
- Spring Cloud Gateway實戰之四:內建predicate小結SpringCloudGateway
- Spring Cloud系列(四):Eureka原始碼解析之客戶端SpringCloud原始碼客戶端
- spring cloud feign 檔案上傳和檔案下載SpringCloud
- 擴充套件Spring Cloud Feign 實現自動降級套件SpringCloud
- spring cloud優雅的處理feign熔斷異常SpringCloud
- Spring Cloud Alibaba 使用Feign進行服務消費SpringCloud
- Spring Cloud Netflix—宣告性REST客戶端:FeignSpringCloudREST客戶端
- Spring cloud 之GatewaySpringCloudGateway
- 【Spring Cloud】之 EurekaSpringCloud
- Spring Cloud Alibaba系列(三)使用feign進行服務呼叫SpringCloud