Feign的工作原理
openFeign爲了實現高度的靈活和舒適的使用體驗,使用了大量的設計模式。簡直是設計模式學習的最佳範本。
初始化過程
- @EnableFeignClients註解將類FeignClientsRegistrar註冊到Spring中。
- 當springboot應用啓動時,FeignClientsRegistrar會掃描所有@FeignClients的註解的類,將這些接口bean註冊到spring容器中。
- 在spring初始化@FeignClients接口bean時,通過FeignClientFactoryBean生成相關接口的代理類。
- FeignClientFactoryBean生成代理時,Feign會爲每個接口方法創建一個RequestTemplate,該對象封裝HTTP請求需要的全部信息,如請求參數名,請求方法等。
- 在實際接口調用時,RequestTemplate生成Request,然後把Request交給Client去處理。
運行時調用棧
- ReflectiveFeign 被反射實例化
- 調用ReflectiveFeign.invoke
- 調用SynchronousMethodHandler.invoke。此處實例化RequestTemplate
- 調用SynchronousMethodHandler.executeAndDecode
- 將RequestTemplate build爲request,調用http客戶端執行
- 將Response Decode爲Object並返回
重要源代碼
在spring-cloud-openfeign-core.jar!/META-INF/spring.factories中,定義了Feign自動配置的相關類。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.openfeign.ribbon.FeignRibbonClientAutoConfiguration,\
org.springframework.cloud.openfeign.FeignAutoConfiguration,\
org.springframework.cloud.openfeign.encoding.FeignAcceptGzipEncodingAutoConfiguration,\
org.springframework.cloud.openfeign.encoding.FeignContentGzipEncodingAutoConfiguration
FeignAutoConfiguration是核心的配置,根據條件分別自動導入了FeignContext, Targeter, feign.Client。這些bean在不同情況下有不同的實現。
設計模式研讀
適配器模式
Feign支持 URLConnection、HTTP Client 和 OKHttp實現遠程調用,Feign通過適配器模式同時支持這些遠程調用庫。
先看一下經典的適配器模式UML圖:
通過抽象出feign.Client接口實現具體的http調用方案的解耦。通過ApacheHttpClient等對象,實現具體http請求方案的適配。
裝飾器模式
Feign通過Ribbon實現了客戶端負載均衡,負載均衡是http請求的一個增強功能,非常適合通過裝飾器模式實現。
經典的裝飾器模式UML圖:
依然還是Client接口,不同的是LoadBalancerFeignClient除了實現了Client外,還擁有一個Client的屬性,LoadBalancerFeignClient在執行http請求時,除了delegate執行具體的http請求以外,還提供客戶端負載均衡調度功能。
代理模式
爲了實現@FeignClient註解的接口,ReflectiveFeign直接使用了JDK的動態代理。
InvocationHandler handler = factory.create(target, methodToHandler);
T proxy = (T) Proxy.newProxyInstance(target.type().getClassLoader(), new Class<?>[]{target.type()}, handler);
ReflectiveFeign類圖:
適配器模式與裝飾器模式的區別
裝飾器與適配器都有一個別名叫做 包裝模式(Wrapper),它們看似都是起到包裝一個類或對象的作用,但是使用它們的目的很不一一樣。適配器模式的意義是要將一個接口轉變成另一個接口,它的目的是通過改變接口來達到重複使用的目的。而裝飾器模式不是要改變被裝飾對象的接口,而是恰恰要保持原有的接口,但是增強原有對象的功能,或者改變原有對象的處理方式而提升性能。所以這兩個模式設計的目的是不同的。
適配器模式與代理模式的區別
裝飾器模式關注於在一個對象上動態的添加業務邏輯,然而代理模式關注於控制對對象的訪問。換句話說,用代理模式在於對它的調用方客戶屏蔽一個業務邏輯的具體實現信息。因此,當我們使用裝飾器模式的時候,我們通常的做法是將原始對象作爲一個參數傳給裝飾者的構造器。當使用代理模式的時候,我們常常在一個代理類中創建一個對象的實例。