Spring Cloud OpenFeign 遠程調用
一、什麼是Feign?
Feign makes writing java http clients easier
,這是官方給出的一個說明,本意翻譯是:Feign使編寫Java http客戶端更容易,Feign
是一個http請求調用的輕量級框架,可以以Java接口註解的方式調用Http請求,Feign可以通過處理註解,將請求模板化,當實際調用的時候,傳入參數,根據參數再應用到請求上,進而轉化成真正的請求。
Feign封裝瞭Http調用流程,更適合面向接口化的編程習慣。
在服務調用的場景中,我們經常調用基於Http協議的服務,而我們經常使用到的遠程調用框架可能有HttpURLConnection、Apache HttpComponnets、OkHttp3 、Forest、Netty等等,這些框架在基於自身的專註點提供瞭自身特性。而從角色劃分上來看,他們的職能是一致的提供Http調用服務。
二、💭理解遠程調用
- 本地調用(Local Procedure Call,簡稱
LPC
) - 遠程調用(Remote Procedure Call,簡稱
RPC
)
feign主要是為我們提供瞭遠程調用的服務,那麼什麼是遠程調用呢? 遠程調用說白瞭可以理解為不同服務之間方法的調用,實質上是兩臺主機間的網絡通信 ,涉及到網絡通信又必然會有序列化、反序列化,編解碼等一些必須要考慮的問題,現在業界內比較流行的一些 RPC 框架,例如:Dubbo
提供的是基於接口的遠程方法調用,通過rpc遠程調用框架,客戶端隻需要知道接口的定義即可調用遠程服務。
而 feign主要就是用來簡化我們發起遠程調用的代碼,以一個遠程調用Github開放的API為🌰:
/** * GitHub客戶端GitHubFeign,訪問GitHub開發平臺API,開放平臺API地址:https://www.apifox.cn/apihub/ * * @author: jacklin * @date: 2022/6/30 21:20 */ @FeignClient(name = "github-client", url = "https://api.github.com") public interface GitHubFeign { /** * 查找github標準庫信息 * <p> * https://api.github.com/search/repositories v * * @author: jacklin * @since 2022/6/30 21:27 **/ @GetMapping(value = "/search/repositories", produces = MediaType.APPLICATION_JSON_VALUE) String searchRepositories(@RequestParam("q") String q); }
第一步: Maven pom文件中引入 OpenFeign 組件。
第二步:客戶端需要定義一個GitHubFeign
接口,裡面定義一個searchRepositories()
方法,可以看到這個接口上添加瞭@FeignClient
註解,而括號裡面指定瞭服務名:github-client
,顯示聲明這個接口是用來遠程調用GitHub API
服務的,url用來指定調用服務的全路徑,其他方法路徑前綴必須與url地址一致,完整的請求路徑URL地址:https://api.github.com/search/repositories
第三步:需要在服務啟動類添加@EnableFeignClients
註解,在服務啟動時,Spring掃描被@FeignClints
修飾的接口,基於動態代理生成本地JDK Proxy代理對象實例,然後將這些代理實例註冊到Spring IOC容器中,當遠程接口被調用時,由Proxy代理實例去完成真正的遠程訪問,並返回結果。
第四步:在Controller引入GitHubFeign服務,完成遠程服務調用:
@RestController @RequestMapping(value = "/github", produces = MediaType.APPLICATION_JSON_VALUE) public class GithubController { @Resource private GitHubFeign gitHubFeign; /** * 查找github標準庫信息 * * @author: jacklin * @since 2022/6/30 21:36 **/ @GetMapping(value = "/searchRepositories") String searchRepositories(@RequestParam(value = "q") String q) { return gitHubFeign.searchRepositories(q); } }
返回結果數據如下👉:
可以看出,feign使得遠程調用跟本地方法是一樣,極大的簡化瞭rpc遠程調用的方式。
三、OpenFeign和Feign的區別
可以認為OpenFeign是Feign的增強版,不同的是OpenFeign支持Spring MVC註解
Feign | OpenFeign |
---|---|
Feign 是Netflix公司寫的,是SpringCloud組件中的一個輕量級RESTful的HTTP服務客戶端,是SpringCloud中的第一代負載均衡客戶端。 |
OpenFeign 的前身是Neflix Feign,Spring Cloud在Feign的基礎上擴展支持瞭SpringMVC的註解,如@RequestMapping等等。OpenFeign的@FeignClient 可以解析SpringMVC的@RequestMapping註解下的接口,並通過動態代理的方式產生實現類,實現類中做負載均衡並調用其他服務。 |
OpenFeign
和Feign
底層都內置瞭Ribbon負載均衡組件,在導入OpenFeign
依賴後無需專門導入Ribbon
依賴,用做客戶端負載均衡,去調用註冊中心服務。
四、OpenFeign核心工作原理
- 通過 @EnableFeignCleints觸發Spring應用程序對classpath中
@FeignClient
修飾類的掃描。 - 解析到 @FeignClient 修飾類後,
Feign
框架通過擴展Spring Bean Deifinition
的註冊邏輯,最終註冊一個FeignClientFacotoryBean
進入Spring
容器 - Spring容器在初始化其他用到 @FeignClient 接口的類時, 獲得的是
FeignClientFacotryBean
產生的一個代理對象Proxy
。 - 基於Java原生的動態代理機制,針對
Proxy
的調用,都會被統一轉發給Feign
框架所定義的一個 InvocationHandler,由該Handler
完成後續的HTTP轉換,發送、接收以及HTTP響應的工作。
五、OpenFeign包掃描原理
要想通過OpenFeign實現遠程調用,就涉及到一個OpenFeign的核心註解:@EnableFeignClient
,根據字面意思可以知道,該註解是開啟OpenFeign的功能,一般都會被添加到我們的啟動類上。
Spring包掃描的大體流程:
- 開啟OpenFeign功能@EnableFeignClients,接著通過@Import(FeignClientsRegistrar.class) 這個import的方式導入FeignClientsRegistrar類,開啟OpenFeign組件的加載。
@SpringBootApplication @EnableFeignClients public class MambaBlockDemoApplication { public static void main(String[] args) { SpringApplication.run(MambaBlockDemoApplication.class, args); } }
FeignClientsRegistrar負責Feign接口的加載,源碼如下:
@Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { //註冊配置 registerDefaultConfiguration(metadata, registry); //註冊FeignClient registerFeignClients(metadata, registry); }
- registerFeignClients()方法會調用findCandidateComponents()方法來查找指定路徑的basePackages下所有被@FeignClients註解修飾的類、接口。
LinkedHashSet<BeanDefinition> candidateComponents = Set<BeanDefinition> findCandidateComponents(String basePackage)
- 隻保留被@FeignClient的修飾的接口。
for (BeanDefinition candidateComponent : candidateComponents) { if (candidateComponent instanceof AnnotatedBeanDefinition) { // verify annotated class is an interface AnnotatedBeanDefinition beanDefinition = (AnnotatedBeanDefinition) candidateComponent; AnnotationMetadata annotationMetadata = beanDefinition.getMetadata(); Assert.isTrue(annotationMetadata.isInterface(), "@FeignClient can only be specified on an interface"); Map<String, Object> attributes = annotationMetadata .getAnnotationAttributes(FeignClient.class.getCanonicalName()); String name = getClientName(attributes); registerClientConfiguration(registry, name, attributes.get("configuration")); //註入到Spring容器中 registerFeignClient(registry, annotationMetadata, attributes); } }
六、總結
本文通過遠程調用的GitHub開放API用到的OpenFeign作為示例代碼作為入口進行講解。然後以圖解+解讀源碼的方式深入剖析瞭OpenFeign的運行機制和架構設計
到此這篇關於Spring Cloud OpenFeign 遠程調用的文章就介紹到這瞭,更多相關Spring Cloud OpenFeign 內容請搜索WalkonNet以前的文章或繼續瀏覽下面的相關文章希望大傢以後多多支持WalkonNet!
推薦閱讀:
- feign 打印日志不顯示的問題及解決
- 剖析SpringCloud Feign中所隱藏的坑
- 一篇文章教你如何在SpringCloud項目中使用OpenFeign
- 淺試仿 mapstruct實現微服務編排框架詳解
- SpringCloud升級2020.0.x版之OpenFeign簡介與使用實現思路