OpenFeign學習(七):Spring Cloud OpenFeign的使用

說明

通過之前的幾篇博文,我簡單介紹了OpenFeign的使用及其工作原理。OpenFeign的易用性和擴展性讓人印象深刻。接下來,我將繼續學習Spring是如何對OpenFeign進行集成支持,使其在Spring Cloud 微服務體系中發揮着重要的作用。在本篇博文中,我將結合官方文檔介紹Spring Cloud OpenFeign,瞭解其基本使用方式及功能特性。

進行服務間的調用無外乎HTTP請求或者RPC調用,在Spring Cloud 微服務體系中也支持了這兩種方式。分別是以HTTP請求爲基礎的Spring Cloud OpenFeign 和阿里的dubbo。Spring Cloud OpenFeign 則是以OpenFign爲基礎,通過自動裝配將其集成到Spring Boot應用中,納入到Spring體系中。

通過官方文檔我們可以初步瞭解Spring Cloud對OpenFeign做了那些改造支持。

Spring Cloud adds support for Spring MVC annotations and for using the same HttpMessageConverters used 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.

可以看到Spring Cloud添加了對Spring MVC註解的支持和Spring Web使用的HttpMessageConverters, 並且集成了Ribbon 和 Eureka,提供了可以進行負載均衡了Http Client。

接下來,通過簡單項目介紹如何使用Spring Cloud OpenFeign。

正文

快速上手

首先引入Spring Cloud OpenFeign 依賴,同時因爲基於Eureka的服務註冊發現,還要引入Eureka-Client 依賴。基於Spring Boot 2.1.14版本:

<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>

引入後,在項目啓動類分別加上@EnableDiscoveryClient和@EnableFeignClients註解:

@EnableDiscoveryClient
@EnableFeignClients
@SpringBootApplication
public class Feign2ClientApplication {

	public static void main(String[] args) {
		SpringApplication.run(Feign2ClientApplication.class, args);
	}

}

在application.yml中配置項目名稱,端口和註冊中心Eureka地址:

spring:
  application:
    name: feign2-client

server:
  port: 2003
eureka:
  client:
    service-url:
      defaultZone: http://localhost:1001/eureka/

創建服務接口,使用@FeignClient註解:

@FeignClient(value = "feign2")
public interface Feign2Service {
    
}

至此,OpenFeign的服務已經配置完畢,通過@Autowired自動注入進行服務調用。

@Autowired
private Feign2Service feign2Service;

可以看到與之前OpenFeign的使用方式相比,我們不再需要使用其他註解配置,不用進行手動創建Feign Client 直接使用SpringMVC的註解, @FeignClient註解即可。同時,Spring Cloud OpenFeign 也支持了手動創建Feign Client,這種方式與OpenFeign相似,這裏不再贅述,更多請看官方文檔。

在@FeignClient註解的value值表示client名稱,該名稱被用來創建Ribbon load-balancer或者 Spring Cloud LoadBalancer 。負載均衡器通過該名稱進行服務端物理地址的獲取,如果項目是eureka-client,則通過eureka註冊中心進行服務地址解析。

同時,如果項目沒有使用eureka註冊中心,@FeignClient註解也支持通過配置url參數來指定服務端的url。同時,文檔提到也可以使用SimpleDiscoveryClient,並配置服務地址列表。

If you don’t want to use Eureka, you can simply configure a list of servers in your external configuration using SimpleDiscoveryClient.

沒有eureka註冊中心,通過url指定服務地址:

@FeignClient(value = "feign2", url = "http://localhost:2003")
public interface Feign2Service {

}

文檔提到,爲了保持向後兼容性,Rabbion作爲默認的負載均衡器實現。但是由於Spring Cloud Netfix Ribbon項目已經進入維護狀態,官方建議使用Spring Cloud LoadBalancer進行替代。可以設置spring.cloud.loadbalancer.ribbon.enabled 值爲false進行配置。

自定義配置

先通過文件上傳示例代碼來了解如何修改Spring Cloud OpenFeign的默認配置:

在OpenFeign的feign-form項目中,我們瞭解瞭如何實現表單提交,主要是配置Encoder。在Spring中,我們需要配置SpringFormEncoder。

這裏不需要引入額外的依賴,在spring-cloud-starter-openfeign依賴中,已經引入了feign-java8依賴,該依賴包含了feign-form和feign-form-spring。

@FeignClient(value = "feign2", configuration = Feign2Service.MultipartSupportConfig.class)
public interface Feign2Service {

    @PostMapping(value = "/uploadFile", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    String handleFileUpload(@RequestPart(value = "file") MultipartFile file);

    @Configuration
    class MultipartSupportConfig{
        @Bean
        public SpringFormEncoder feignFormEncoder(){
            return new SpringFormEncoder();
        }
    }
}

可以看到,先配置生成了SpringFormEncoder的bean對象,然後在@FeignClient註解中配置configuration值來修改默認Encoder。
這裏使用的並不是spring標準的encoder配置,標準配置請看文檔 feign-form 或者這篇博文《SpringCloud Feign Decoder》

通過文檔我們可以瞭解到,Spring Cloud Netflix爲feign提供了一些默認配置:

  • Decoder : ResponseEntityDecoder (包含了一個SpringEncoder)
  • Encoder : SpringEncoder
  • Logger : Slf4jLogger
  • Controct : SpringMvcControct
  • Feign.Builder : HystrixGeign.Builder
  • Client : 如果Ribbon可用則爲LoadBalancerFeignClient對象,否則若Spring Cloud Balancer可用,則使用FeignBlockingLoadBalancerClient對象,兩個都不可用時,則使用默認的feign client。

注意,spring-cloud-starter-openfeign依賴已經同時引入了spring-cloud-starter-netflix-ribbon 和 spring-cloud-starter-loadbalancer。

對於OpenFeign的默認Client : OkHttpClient和ApacheHttpClient,可以通過設置feign.okhttp.enabled 或 feign.httpclient.enabled 值爲true進行啓用。同時也可以自定義HttpClient。

在之前OpenFeign的使用介紹中,我們瞭解到OpenFeign有默認的重試器Retryer和對QueryMap的支持。但是Spring Cloud OpenFeign並沒有對以下配置進行默認實現:

  • Logger.Level
  • Retryer
  • ErrorDecoder
  • Request.Options
  • Collection
  • SetterFactory
  • QueryMapEncoder

通過以上文件傳輸方法配置可知,Spring Cloud OpenFeign提供了在@FeignClient註解中設置configuration值來覆蓋默認配置的方法。對此我們可以通過該方式來配置以上自實現的Retryer, Interceptor, Logger.Level等。

@Configuration
class Config{
    @Bean
    public Retryer retryer() {
        return new MyRetryer();
    }

    @Bean
    public RequestInterceptor interceptor() {
        return new RequestHeaderInterceptor();
    }
    
    @Bean
    public Logger.Level level() {
        return Logger.Level.FULL;
    }
}
@FeignClient(value = "feign2", configuration = Feign2Service.Config.class)
public interface Feign2Service {
 
}

同時,我們也可以通過配置文件的方式對Feign進行配置,在application.yml中進行一下配置:

feign:
  client:
    config:
      feign2:
        connectTimeout: 5000
        readTimeout: 5000
        loggerLevel: full
        encoder: feign.form.spring.SpringFormEncoder
        requestInterceptors:
          - com.example.feign2.interceptor.RequestHeaderInterceptor

注意,config下級爲對應feign的名稱

對於所有Feign的默認配置,可以像以上展示的那樣通過在@EnableFeignClients註解中設置defaultConfiguration值進行配置,又或者通過配置文件,將config下級對應feign的名稱設置爲default

如果同時在註解中設置了Configuration 對象 和在配置文件中進行了配置,此時配置文件的屬性值會覆蓋註解中的配置。如果想改變此優先級,可以設置feign.client.default-to-properties值爲false。

對於OpenFeign日誌的支持,在只有log level爲debug時,纔會輸出日誌。因此需要在配置文件中設置對應類的日誌等級:

logging:
  level:
    com:
      example:
        feign2:
          service: debug

關於日誌等級的分類,在之前的博文中我已經介紹過,在此不再贅述。

關於更多了Spring Cloud OpenFeign的默認配置值,請看文檔Common application properties

@QueryMap

在之前OpenFeign介紹中,我們已經知道OpenFeign使用@QueryMap註解將POJO轉換爲GET請求參數。但是Spring Clound OpenFeign 並不支持該註解,因爲它缺少Value屬性。

爲此,Spring Cloud OpenFeign提供了一個等效的註解@SpringQueryMap,該註解可以將一個POJO或者是Map參數轉換爲請求參數。

public class User {

    private String uname;
    private String pwd;
    
    ...getter setter
}
@FeignClient(value = "feign2")
public interface Feign2Service {
    @GetMapping("/hi")
    String hi(@SpringQueryMap User user);
}

與@QueryMap註解一樣,會將POJO的參數名稱或者Map的key值作爲請求的參數名稱。若需要改動,則可以自實現QueryMapEncoder bean。

至此,對Spring Cloud OpenFeign的簡單使用及配置已經介紹完畢,接下來我將繼續對Sprig Cloud OpenFeign 其他功能特性進行學習總結。


參考資料:
https://cloud.spring.io/spring-cloud-static/spring-cloud-openfeign/2.2.3.RELEASE/reference/html/#feign-querymap-support

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章