微服務呼叫元件 Feign

HuDu發表於2022-08-02

前言

Java 專案中如何實現介面呼叫

1、Httpclinet

HtpClient 是Apache Jakarta Common下的子專案,用來提供高效的、最新的、功能豐富的支援Htp協議的客戶端程式設計工具包,並且它支援HTTP協議最新版本和建議。HtpClient相比傳統JDK自帶的URLConnection,提升
了易用性和靈活性,使客戶端傳送HTTP請求變得容易,提高了開發的效率。

2、OkHttp

一個處理網路請求的開源專案, 安卓端最火的輕量級框架,由Square公司貢獻,於替代HttpUrlConnection 和Apache HttpClient。OkHttp 擁有簡潔的 API、高效的效能,技持多種協議(HTTP/2SPDY)3、HttpURLConnection

HttpURLConnection是Java的標準類,它繼承自URLConnection,可用於向指定網站傳送GET請求、POST 請求。HttpURLConnection 使用比較複雜,不像HttpClient那樣容易使用。

4、RestTemplate WebClinet
RestTemplate是Spring提供的用於訪問Rest服務的客F端,RestTemplate 提供了多種便捷訪問遠端HTTP服務的方法,能夠大大提高客戶端的編寫效率。上面介紹的是最常見的幾種呼叫介面的方法,我們下面要介紹的方法比上面的更簡單、方便,它就是Feign。

一、什麼是 Feign

Feign是Netix開發的宣告式、模板化的HTTP客戶端,其靈感來自Retrofit、 JAXRS-2 .0以及WebSocket。Feign可幫助我們更加便捷、優雅地呼叫HTTP API。Feign支援多種註解,例如Feign自帶的註解或者JAX-RS註解等。

SpringCloud OpenFeign 對 Feign 進行了增強,對其支援 Spring Mvc 註解,另外還整合了 Ribbon 和 Nacos,從而使得 Feign 的使用更加方便

1.1、優勢

Feign可以做到使用 HTTP 請求遠端服務時就像呼叫本地方法一樣的體驗, 開發者完全感知不到這是遠端方法,更感知不到這是個 HTTP 請求。它像 Dubbo 一樣, consumer 直接呼叫介面方法呼叫 provider,而不需要透過常規的 Http Client 構造請求再解析返回資料。它解決了讓開發者呼叫遠端介面就跟呼叫本地方法一樣, 無需關注與遠端的互動細節,更無需關注分散式環境開發。

二、Spring Cloud Alibaba 快讀整合 OpenFeign

2.1、引入依賴

    <dependencies>
        <!--1.新增 openfeign 依賴,需要引入 spring-cloud 的依賴-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
    </dependencies>

2、新增 feign 介面和方法

/**
 * name 指定呼叫 rest 介面所對應的服務名
 * path 指定呼叫 rest 介面所在的 StockController 指定的 @RequestMapping
 */
@FeignClient(name = "stock-server",path = "/stock")
public interface StockFeignService {
    // 宣告需要呼叫的 rest 介面對應的方法
    @RequestMapping("/reduce")
    String reduce();
}

對比實際的介面程式碼

微服務呼叫元件 Feign

2.3、發起呼叫,像呼叫本地方法一樣呼叫遠端服務

@RestController
@RequestMapping(value = {"/order"})
public class OrderController {

    @Autowired
    private StockFeignService stockFeignService;

    @RequestMapping("/add")
    public String add() {
        System.out.println("下單成功!");
        String message = stockFeignService.reduce();
        return "Hello Feign " + message;
    }
}

2.4、呼叫端在啟動類加上新增@EnableFeignClients註解

@SpringBootApplication
@EnableFeignClients
public class OrderServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(OrderServerApplication.class,args);
    }
}

目錄結構如下

微服務呼叫元件 Feign

啟動 stock-serverorderopefeignserver服務,訪問http://localhost:8040/order/add

三、Spring Cloud OpenFeign 的自定義配置及使用

Feign 提供了很多擴充套件機制,讓使用者可以更加靈活使用。

3.1、日誌配置

有時候我們遇到 Bug,比如介面呼叫失敗、引數沒收到等問題,或者想看看呼叫效能,就需要配置 Feign 的日誌了,以此讓 Feign 把請求資訊輸出來。

專案結構如下

微服務呼叫元件 Feign

3.1.1、自定義一個配置類,指定日誌級別

/**
 * 全域性配置:當使用 @Configuration 會將配置作用所有的服務提供方
 * 區域性配置:如果只想針對某一個服務進行配置,不用 @Configuration
 */
@Configuration
public class FeignConfig {
    @Bean
    public Logger.Level feignLoggerLevel() {
        return Logger.Level.FULL;
    }
}

透過原始碼可以看到日誌等級有 4 種,分別是

  • NONE(效能最佳,適用於生產):不記錄任何日誌(預設值)
  • BASIC(適用於生產環境追蹤問題):僅記錄請求方法、URL、響應狀態以及執行時間。
  • HEADERS:記錄 BASIC 級別基礎上,記錄請求和響應的 header
  • FULL(比較適用於開發以及測試環境定位問題):記錄請求和響應時間的 header、body和後設資料

3.1.2、區域性配置,讓呼叫的微服務生效,在@FeignClient註解中指定使用的配置

@FeignClient(name = "product-server",path = "/product",configuration = FeignClient.class)
public interface ProductFeignService {
    @RequestMapping("/{id}")
    String get(@PathVariable("id") Integer id);
}

3.1.3、在 yml 配置檔案中指定 Client 的日誌級別才能正常輸出日誌,格式是”logging.level.feign介面包路徑=debug”

# springboot 預設的日誌級別是 info,feign 的 debug 日誌級別不會輸出
logging:
  level:
    # 指定包的日誌級別
    com.hudu.order.feign: debug

詳細日誌資訊

微服務呼叫元件 Feign

補充:區域性配置可以在 yml 中配置

對應屬性配置類:org.springframework.cloud.openfeign.FeignClientProperties

# feign 日誌區域性配置
feign:
  client:
    config:
      # 對應微服務
      product-server:
        loggerLevel: FULL

3.2、契約配置

Spring Cloud 在 Feign 的基礎上做了擴充套件,使用 Spring MVC 的註解來完成 Feign 的功能。原生的 Feign 是不支援 Spring MVC 註解的,如果你想在 Spring Cloud 中使用原生的註解方式來定義客戶端也是可以的,透過配置契約來改變這個配置,Spring Cloud 中預設的是 SpringMvcContract.
Spring Cloud 早期版本就是使用的原生的 Feign,隨著 netflix 的停更,替換成了 Open feign

一般使用場景為,SpringCloud 版本升級,保留原生的註解。

3.2.1、修改契約配置,支援 Feign 原生的註解

/**
* 修改契約配置,支援 Feign 原生的註解
*/
@Bean
public Contract feignContract() {
    return new Contract.Default();
}

注意:修改契約配置後,OrderFeignService 不再支援 springmvc註解,需要使用 Feign 原生的註解

3.2.2、OrderFeignService 中配置使用 Feign 原生的註解

@FeignClient(name = "product-server",path = "/product")
public interface ProductFeignService {
    @RequestLine("GET /{userId}")
    String get(@Param("userId") Integer userId);
}

3.2.3、補充,也可以透過 yml 配置契約

# feign 日誌區域性配置
feign:
  client:
    config:
      # 對應微服務
      product-server:
        contract: feign.Contract.Default # 指定 Feign 原生註解契約配置

3.3、超時時間配置

透過 Options 可以配置連線超時時間和讀取超時時間,Options 的第一個引數是連線的超時時間 (ms) ,預設值是2s;第二個是請求處理的超時時間(ms) , 預設值是5s.

3.3.1、全域性配置

/**
* 超時時間配置
*/
public Request.Options options() {
    return new Request.Options(5000,10000);
}

3.3.2、yml 中配置

feign:
  client:
    config:
      # 對應微服務
      product-server:
        # 連線超時時間,預設 2 s
        connectionTimeout: 5000
        # 請求處理超時時間,預設 5 s
        readTimeout: 10000

補充說明:Feign 的底層用的是 Ribbon,但超時時間以 Feign 配置為準。

微服務呼叫元件 Feign

3.4、自定義攔截器實現認證邏輯

public class CustomFeignInterceptor implements RequestInterceptor {
    Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public void apply(RequestTemplate requestTemplate) {
        // 業務邏輯
        String access_token = UUID.randomUUID().toString();
        requestTemplate.header("Authorization", access_token);
        // query String 方式傳參
        requestTemplate.query("id", "111");
        // 佔位符方式,修改掉請求的id
        requestTemplate.uri("/9");
        logger.info("feign 攔截器!");
    }
}


// 全域性配置
@Configuration
public class FeignConfig {
  @Bean
  public Logger.Level feignLoggerLevel() {
  return Logger.Level.FULL;
  }
  @Bean
  public CustomFeignInterceptor customFeignInterceptor() {
  return new CustomFeignInterceptor();
  }
}

補充:可以在配置檔案中配置

feign:
  client:
    config:
      # 對應微服務
      product-server:
        # 配置攔截器
        requestInterceptors[0]:
          com.hudu.order.interceptor.feign.CustomFeignInterceptor

product-server 端可以透過 @RequestHeader 獲取請求引數,建議在 filter,Interceptor 中處理。

本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章