Spring?Cloud?OpenFeign?遠程調(diào)用
一、什么是Feign?
Feign makes writing java http clients easier,這是官方給出的一個說明,本意翻譯是:Feign使編寫Java http客戶端更容易,Feign是一個http請求調(diào)用的輕量級框架,可以以Java接口注解的方式調(diào)用Http請求,F(xiàn)eign可以通過處理注解,將請求模板化,當(dāng)實際調(diào)用的時候,傳入?yún)?shù),根據(jù)參數(shù)再應(yīng)用到請求上,進而轉(zhuǎn)化成真正的請求。
Feign封裝了Http調(diào)用流程,更適合面向接口化的編程習(xí)慣。
在服務(wù)調(diào)用的場景中,我們經(jīng)常調(diào)用基于Http協(xié)議的服務(wù),而我們經(jīng)常使用到的遠程調(diào)用框架可能有HttpURLConnection、Apache HttpComponnets、OkHttp3 、Forest、Netty等等,這些框架在基于自身的專注點提供了自身特性。而從角色劃分上來看,他們的職能是一致的提供Http調(diào)用服務(wù)。
二、??理解遠程調(diào)用
- 本地調(diào)用(Local Procedure Call,簡稱
LPC) - 遠程調(diào)用(Remote Procedure Call,簡稱
RPC)
feign主要是為我們提供了遠程調(diào)用的服務(wù),那么什么是遠程調(diào)用呢? 遠程調(diào)用說白了可以理解為不同服務(wù)之間方法的調(diào)用,實質(zhì)上是兩臺主機間的網(wǎng)絡(luò)通信 ,涉及到網(wǎng)絡(luò)通信又必然會有序列化、反序列化,編解碼等一些必須要考慮的問題,現(xiàn)在業(yè)界內(nèi)比較流行的一些 RPC 框架,例如:Dubbo提供的是基于接口的遠程方法調(diào)用,通過rpc遠程調(diào)用框架,客戶端只需要知道接口的定義即可調(diào)用遠程服務(wù)。

而 feign主要就是用來簡化我們發(fā)起遠程調(diào)用的代碼,以一個遠程調(diào)用Github開放的API為??:
/**
* GitHub客戶端GitHubFeign,訪問GitHub開發(fā)平臺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注解,而括號里面指定了服務(wù)名:github-client,顯示聲明這個接口是用來遠程調(diào)用GitHub API服務(wù)的,url用來指定調(diào)用服務(wù)的全路徑,其他方法路徑前綴必須與url地址一致,完整的請求路徑URL地址:https://api.github.com/search/repositories
第三步:需要在服務(wù)啟動類添加@EnableFeignClients注解,在服務(wù)啟動時,Spring掃描被@FeignClints修飾的接口,基于動態(tài)代理生成本地JDK Proxy代理對象實例,然后將這些代理實例注冊到Spring IOC容器中,當(dāng)遠程接口被調(diào)用時,由Proxy代理實例去完成真正的遠程訪問,并返回結(jié)果。
第四步:在Controller引入GitHubFeign服務(wù),完成遠程服務(wù)調(diào)用:
@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);
}
}返回結(jié)果數(shù)據(jù)如下??:

可以看出,feign使得遠程調(diào)用跟本地方法是一樣,極大的簡化了rpc遠程調(diào)用的方式。
三、OpenFeign和Feign的區(qū)別
可以認為OpenFeign是Feign的增強版,不同的是OpenFeign支持Spring MVC注解
| Feign | OpenFeign |
|---|---|
Feign是Netflix公司寫的,是SpringCloud組件中的一個輕量級RESTful的HTTP服務(wù)客戶端,是SpringCloud中的第一代負載均衡客戶端。 | OpenFeign的前身是Neflix Feign,Spring Cloud在Feign的基礎(chǔ)上擴展支持了SpringMVC的注解,如@RequestMapping等等。OpenFeign的@FeignClient可以解析SpringMVC的@RequestMapping注解下的接口,并通過動態(tài)代理的方式產(chǎn)生實現(xiàn)類,實現(xiàn)類中做負載均衡并調(diào)用其他服務(wù)。 |
OpenFeign和Feign底層都內(nèi)置了Ribbon負載均衡組件,在導(dǎo)入OpenFeign依賴后無需專門導(dǎo)入Ribbon依賴,用做客戶端負載均衡,去調(diào)用注冊中心服務(wù)。
四、OpenFeign核心工作原理
- 通過 @EnableFeignCleints觸發(fā)Spring應(yīng)用程序?qū)lasspath中
@FeignClient修飾類的掃描。 - 解析到 @FeignClient 修飾類后,
Feign框架通過擴展Spring Bean Deifinition的注冊邏輯,最終注冊一個FeignClientFacotoryBean進入Spring容器 - Spring容器在初始化其他用到 @FeignClient 接口的類時, 獲得的是
FeignClientFacotryBean產(chǎn)生的一個代理對象Proxy。 - 基于Java原生的動態(tài)代理機制,針對
Proxy的調(diào)用,都會被統(tǒng)一轉(zhuǎn)發(fā)給Feign框架所定義的一個 InvocationHandler,由該Handler完成后續(xù)的HTTP轉(zhuǎn)換,發(fā)送、接收以及HTTP響應(yīng)的工作。
五、OpenFeign包掃描原理
要想通過OpenFeign實現(xiàn)遠程調(diào)用,就涉及到一個OpenFeign的核心注解:@EnableFeignClient,根據(jù)字面意思可以知道,該注解是開啟OpenFeign的功能,一般都會被添加到我們的啟動類上。
Spring包掃描的大體流程:
- 開啟OpenFeign功能@EnableFeignClients,接著通過@Import(FeignClientsRegistrar.class) 這個import的方式導(dǎo)入FeignClientsRegistrar類,開啟OpenFeign組件的加載。
@SpringBootApplication
@EnableFeignClients
public class MambaBlockDemoApplication {
public static void main(String[] args) {
SpringApplication.run(MambaBlockDemoApplication.class, args);
}
}FeignClientsRegistrar負責(zé)Feign接口的加載,源碼如下:
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
//注冊配置
registerDefaultConfiguration(metadata, registry);
//注冊FeignClient
registerFeignClients(metadata, registry);
}- registerFeignClients()方法會調(diào)用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);
}
}六、總結(jié)
本文通過遠程調(diào)用的GitHub開放API用到的OpenFeign作為示例代碼作為入口進行講解。然后以圖解+解讀源碼的方式深入剖析了OpenFeign的運行機制和架構(gòu)設(shè)計
到此這篇關(guān)于Spring Cloud OpenFeign 遠程調(diào)用的文章就介紹到這了,更多相關(guān)Spring Cloud OpenFeign 內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java根據(jù)表達式獲取對象中的值及設(shè)置值的例子
這篇文章主要介紹了Java根據(jù)表達式獲取對象中的值及設(shè)置值的例子,本文給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2025-03-03
淺談js文件引用方式及其同步執(zhí)行與異步執(zhí)行
下面小編就為大家?guī)硪黄獪\談js文件引用方式及其同步執(zhí)行與異步執(zhí)行。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2016-10-10
關(guān)于eclipse中運行tomcat提示端口被占用的4種解決
這篇文章主要介紹了關(guān)于eclipse中運行tomcat提示端口被占用的4種解決,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2023-01-01

