Feign遠程調用


一、先看在此之前,我們服務之間需要進行調用的時候使用的restTemplate,代碼示例如下:

String url = "http://userservice/user/"+userId; User user = restTemplate.getForObject(url , User.class);

這種方法需要先定義一個url,再使用restTemplate的api向這個路徑去發送請求

思考這種方式的缺陷:在實際開發中,一個url會有很復雜的情況出現,參數可能多達幾十個,此時要維護一個url將是一件很恐怖的事情。其次,代碼的可讀性也比較差

因此,有一種新的方式去發起遠程調用,也就是Feign,feign是一種聲明式的http客戶端,其作用就是幫助開發者優雅的實現遠程調用,極其優雅

 

二、使用方式

  1、引入Feign的依賴

<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency>

  2、在服務消費者啟動類上添加@EnableFeignClient注解,開啟Feign的功能

  3、編寫Feign的客戶端(在服務消費者中新建一個接口,內容如下)

@FeignClient("userservice") //這個注解的默認屬性是name/value,值是服務提供者的服務名稱 public interface UserClient { @GetMapping("/user/{id}") //這里是要調用服務提供者的接口的地址 User findById(@PathVariable("id") Long id); //這里是標識服務提供者的接口的方法,方法名可以不一樣,返回值、參數列表必須一樣 }

     這個客戶端主要是基於springMVC的注解來聲明遠程調用的信息,比如:

服務名稱:userservice

* 請求方式:GET

* 請求路徑:/user/{id}

* 請求參數:Long id

* 返回值類型:User

  聲明了這些信息,Feign就可以幫助我們發送http請求了,無需自己使用restTemplate去發送了

     注:FeignClient注解屬性的說明

          

 

 

   4、發起調用

    在需要調用的地方注入定義浩的接口(這里是UserClient),再用注入的接口對象去調用對應的 "方法"

@Resource
private UserClient userClient;

@GetMapping("{orderId}") public Order queryOrderByUserId(@PathVariable("orderId") Long orderId) { // 根據id查詢訂單並返回 Order order = orderService.queryOrderById(orderId);
//restTemplate方式遠程調用 //定義請求的路徑 //String url = "http://userservice/user/"+order.getUserId(); //發送get請求 //User user = restTemplate.getForObject(url, User.class); //Feign方式遠程調用 User user1 = userClient.getById(order.getUserId());
order.setUser(user1);
return order; }

 

三、總結使用方法:

  ①引入依賴

  ②再服務消費者的啟動類上添加@EnableFeignClients注解

  ③編寫FeignClient接口

  ④使用FeignClient接口中定義的 ”方法“ 遠程調用

 

四、Feign的自定義配置

  1、Feign可以支持很多的自定義配置,大概有如下這些:

類型 作用 說明
feign.Logger.Level 修改日志級別 包含四種不同的級別:NONE、BASIC、HEADERS、FULL
feign.codec.Decoder 響應結果的解析器 http遠程調用的結果做解析,例如解析json字符串為java對象
feign.codec.Encoder 請求參數編碼 將請求參數編碼,便於通過http請求發送
feign. Contract 支持的注解格式 默認是SpringMVC的注解
feign. Retryer 失敗重試機制 請求失敗的重試機制,默認是沒有,不過會使用Ribbon的重試

   一般情況下,默認值就能滿足我們使用,如果要自定義時,只需要創建自定義的@Bean覆蓋默認Bean即可

  

  2、以日志為例,實現自定義配置(兩種方式)

    ①基於配置文件修改feign的日志級別(可針對某個服務,也可針對所有的服務):

feign: client: config: userservice: # 如果針對某個服務,這里就寫對應的服務名,如果針對所有服務,就寫default loggerLevel: FULL # 日志的級別(有NONE、BASIC、HEADERS、FULL)

    日志的級別分為四種:

NONE:不記錄任何日志信息,這是默認值

BASIC:僅記錄請求的方法,URL以及響應狀態碼和執行時間

HEADERS:在BASIC的基礎上,額外記錄了請求和響應的頭信息

FULL:記錄所有請求和響應的明細,包括頭信息、請求體、元數據

 

    ②基於Java代碼,在項目中聲明一個類,將Logger.Level對象注冊到spring容器中

public class DefaultFeignConfiguration { @Bean public Logger.Level feignLogLevel(){ return Logger.Level.BASIC; // 日志級別為BASIC(枚舉類)  } }

      Ⅰ、如果想要自定義配置全局生效,則在啟動類的@EnableFeignClients注解中放入這個類

        @EnableFeignClients(defaultConfiguration = DefaultFeignConfiguration .class

      

      Ⅱ、如果想要自定義配置局部生效,則在對應的@FeignClient注解中放入這個類

         @FeignClient(value = "userservice", configuration = DefaultFeignConfiguration .class

 

五、Feign的優化建議:

  1、Feign底層發起http請求,依賴於其它的框架。其底層客戶端實現包括:

URLConnection:默認實現,不支持連接池

Apache HttpClient :支持連接池

OKHttp:支持連接池

   因此,想要提升Feign的性能主要手段就是使用連接池代替默認的URLConnection

  2、實例使用Apache HttpClient

    ①引入HttpClient的依賴

<!--httpClient的依賴 --> <dependency> <groupId>io.github.openfeign</groupId> <artifactId>feign-httpclient</artifactId> </dependency>

    ②在配置文件中配置連接池的一些配置:

feign: client: config: default: # default全局的配置 loggerLevel: BASIC # 日志級別,BASIC就是基本的請求和響應信息 httpclient: enabled: true # 開啟feign對HttpClient的支持 max-connections: 200 # 最大的連接數 max-connections-per-route: 50 # 每個路徑的最大連接數

    ③總結Feign的優化建議:

      Ⅰ、日志級別盡量使用BASIC或者使用NONE

      Ⅱ、使用帶連接池的Feign客戶端

 

 

六、Feign的最佳實踐(所謂最近實踐,就是使用過程中總結的經驗,最好的一種使用方式)

  ①使用過程中我們可以發現,Feign的客戶端與服務提供者的controller代碼非常相似,所以我們利用繼承的方式來抽取共同的部分:

    Ⅰ、定義一個API接口,利用定義方法,基於springMVC注解做聲明

    Ⅱ、Feign客戶端和Controller都繼承該接口

                 

 

     Ⅲ、不足之處:

        服務提供方、服務消費方緊耦合

        參數列表中的注解映射並不會繼承,因此Controller中必須再次聲明方法、參數列表、注解

 

  ②抽取方式

    將Feign的Client抽取為獨立模塊,並且把接口有關的POJO、默認的Feign配置都放到這個模塊中,提供給所有消費者使用

                

 

   ③抽取步驟

    Ⅰ、創建一個module,命名為feign-api

    Ⅱ、在feign-api的pom中引入依賴(包括geign的starter依賴和Apache HttpClient依賴)

    Ⅲ、將之前服務消費者中編寫的UserClient、User、DefaultFeignConfiguration都提取到feign-api子項目中

    Ⅳ、在原先的服務消費者中使用抽取的feign-api

      1、首先,刪除order-service中的UserClient、User、DefaultFeignConfiguration等類或接口

      2、在服務的消費者中引入feign-api的依賴

      3、修改服務中所有與上述三個組件有關的部分,改成feign-api包中引入

      4、重啟,(發現會報錯)

        報錯原因:UserClient在另一個項目的包中,所以服務的消費者無法掃描到UserClient組件

        解決方式:(兩種)

          ①指定Feign應該掃描的包(不建議使用,這樣把沒用到的也引入了,造成浪費)

            @EnableFeignClients(basePackages = "cn.itcast.feign.clients")

          ②指定需要加載的Client的接口:(推薦使用,按需引用)

            @EnableFeignClients(clients = {UserClient.class})

      

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM