事情是這樣的,最近在代碼中須要使用 Feign 調用第三方服務。因此就是標準的一套操做:java
@EnableFeignClients
註解注入 Bean。@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
在調試代碼的時候出現一個奇怪的錯誤,引入的 Bean 竟然爲空,這讓我感到異常困惑,加上對 Spring 不是很熟悉,讓我頓感不安。json
一頓百度、谷歌打斷點調試,其中有個說的有道理api
EnableFeignClients
掃描路徑與 ComponentScan
掃描衝突檢查後配置後發現沒有問題。數組
直到查看到代碼中關於兩個 Feign 的導入才發現到了端倪。安全
import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.cloud.netflix.feign.FeignClient;
終於問題的緣由找到了項目中 FeignClient
與 EnableFeignClients
的版本不一致致使 Bean 注入失敗。 @Autowired(required = false)
忽略了 Bean 的注入。最終致使NullPointerException
。bash
本覺得找到問題就能夠解決了,可是面對第三方的 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 是 Netflix 開發的聲明式、模板化的HTTP客戶端, Feign 能夠幫助咱們更快捷、優雅地調用 HTTP。
簡單的說 Feign 經過將註解處理爲模板化請求來工做。參數在輸出以前直接應用於這些模板。
Spring Cloud Feign是基於Netflix feign實現,整合了Spring Cloud Ribbon和Spring Cloud Hystrix,除了提供這二者的強大功能外,還提供了一種聲明式的Web服務客戶端定義的方式。
具體的能夠參考 stackoverflow 的討論。
主要說明 EnableFeignClients
與 FeignClient
。
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。 |