記一次 Feign 的坑

事件回顧

原由

事情是這樣的,最近在代碼中須要使用 Feign 調用第三方服務。因此就是標準的一套操做:java

    1. 引入第三方服務 Jar 包。
    1. @EnableFeignClients 註解注入 Bean。
    1. @Autowired 引入 Bean。

而後也沒有在乎到 Idea 已經有警告了,直接啓動服務了。而後就出現以下錯誤:git

Description:

Field api in com.xxx.service.impl.ServiceImpl required a bean of type 'com.xxx.api.Api' that could not be found.

The injection point has the following annotations:
	- @org.springframework.beans.factory.annotation.Autowired(required=true)

Action:

Consider defining a bean of type 'com.xxx.api.Api' in your configuration.
複製代碼

PS: Idea 的告警爲 Could not autowire. No beans of 'Api' type found.github

通過

而後結合 Idea 的警告與日誌直接就配置 Autowired 的參數 @Autowired(required = false)算是暫時解決了項目能啓動以及 Idea 的警告。web

可是。。。 可是。。。 可是。。。spring

image.png

在調試代碼的時候出現一個奇怪的錯誤,引入的 Bean 竟然爲空,這讓我感到異常困惑,加上對 Spring 不是很熟悉,讓我頓感不安。json

一頓百度、谷歌打斷點調試,其中有個說的有道理api

  • EnableFeignClients 掃描路徑與 ComponentScan 掃描衝突

檢查後配置後發現沒有問題。數組

直到查看到代碼中關於兩個 Feign 的導入才發現到了端倪。安全

  • import org.springframework.cloud.openfeign.EnableFeignClients;
  • import org.springframework.cloud.netflix.feign.FeignClient;

終於問題的緣由找到了項目中 FeignClientEnableFeignClients 的版本不一致致使 Bean 注入失敗。 @Autowired(required = false) 忽略了 Bean 的注入。最終致使NullPointerExceptionbash

結果

本覺得找到問題就能夠解決了,可是面對第三方的 Jar 包,顯然直接修改代碼是不可能的。

那替換本身的呢?

那也是不行的,由於第四方服務、第五方服務都是 openfeign 的註解。

思來想去最後只能在本身的項目中基於 openfeign 的實現與原業務相同的接口。其實就是複製代碼更改註解,其餘的啥也不是。代碼大體以下:

import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

@FeignClient( name = "service", path = "/api/v1")
public interface ApiFeignClient {
    @RequestMapping( method = {RequestMethod.POST}, value = {"/query"}, consumes = {"application/json"} )
    ResponseBody query(@RequestBody RequestDto reqDto);

    @RequestMapping( method = {RequestMethod.GET}, value = {"/list"}, consumes = {"application/json"} )
    ResponseBody list(@RequestParam("name") String name);
}
複製代碼

而後代碼中使用咱們本身的 Bean,相似下面:

@Autowired
private ApiFeignClient api;
複製代碼

這樣有缺點就是第三方服務的邏輯更改並不能同步到你的服務。因此這是一種後知後覺的方法去解決問題。本質上仍是須要第三方服務實現基於 openfeign 的 Jar 包。

Feign 總結

通過這事以後,也查了不少資料,看了不少博客。這裏總結一下關於 Feign 的知識點。

Feign 是什麼?

Feign 是 Netflix 開發的聲明式、模板化的HTTP客戶端, Feign 能夠幫助咱們更快捷、優雅地調用 HTTP。

簡單的說 Feign 經過將註解處理爲模板化請求來工做。參數在輸出以前直接應用於這些模板。

Netflixfeign 與 Openfeign 區別

Spring Cloud Feign是基於Netflix feign實現,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供這二者的強大功能外,還提供了一種聲明式的Web服務客戶端定義的方式。

具體的能夠參考 stackoverflow 的討論。

註解的參數

主要說明 EnableFeignClientsFeignClient

  • EnableFeignClients 註解參數
名稱 解釋
value 爲 basePackages 屬性的別名,容許使用更簡潔的書寫方式。
basePackages 設置自動掃描帶有 @FeignClient 註解的基礎包路徑。
basePackageClasses basePackages 屬性的安全替代屬性。掃描 @FeignClient修飾的類。
defaultConfiguration 該屬性用來自定義全部Feign客戶端的配置,使用 @Configuration進行配置。
clients 設置由 @FeignClient 註解修飾的類列表。注意 clients 不是空數組,則不經過類路徑自動掃描功能來加載 FeignClient。
  • FeignClient 註解參數
名稱 解釋
name、value、serviceId 三者做用基本一致。name指定 FeignClient 的名稱,若是項目使用了 Ribbon,name屬性會做爲微服務的名稱,用於服務發現。serviceId 已經廢棄.
qualifier 指定別名接本沒用過。對應的是 @Qualifier註解
url 指定 FeignClient 調用的地址,通常用於調試程序。
decode404 調用出現 http404 錯誤且該字段位爲true,會調用decoder進行解碼,不然拋出異常
configuration Feign配置類,能夠自定義Feign的 Encoder、Decoder、LogLevel、Contract。
fallback 定義容錯的處理類,當調用遠程接口異常時,會調用對應接口的異常邏輯,注意 fallback 指定的類必須實現 @FeignClient 標記的接口
fallbackFactory 用於生成fallback類示例,實現每一個接口通用的容錯邏輯,減小重複的代碼。
path 定義當前 FeignClient 的統一前綴。
primary 是否將僞代理標記爲主 Bean,默認爲true。

參考資料

相關文章
相關標籤/搜索