1. feign概述
Feign是接口調用的,但是衆所周知接口是不能創建對象的,必須有實現類。而Feign的做法類似於Mybatis中mapper接口的實現,都是利用了動態代理來給接口創建一個代理對象,創建好的代理對象完成真正的調用過程。
2. 案例入門
- Eureka Server:
- 服務提供者:
- 服務調用者feign
複製對應的方法簽名到接口中,並標識對應的註解,以便Spring框架對其進行動態代理創建代理對象:
依次啓動:
3. feign具體步驟
① 先給接口創建對象;
② 代理對象執行進入invoke方法;
③在invoke方法中執行遠程調用;
a. 讀取註解得到要調用的遠程接口,provider/info;
b. 通過ribbon+restTemplate的負載得到一個要調用的真實服務提供者;
c. 發起請求得到響應;
4 . Feign的內部怎麼實現的
- @EnableFeignClients註解中引入了FeignClientsRegistrar類:
- 該類中實現了ImportBeanDefinitionRegistrar,可以將需要創建的對象放在註冊器裏面,以便spring動態代理幫我們創建代理對象:
- 在feign中我們可以將那些接口傳入FeignClientsRegistrar類的以下方法中,將@FeignClient標記的接口放在registry註冊器中,spring之後幫我們創建對象:
- 上面的registerFeignClients()方法會做包掃描,得到所有@FeignClient標記的接口:
- 上面最後一行代碼registerFeignClient(registry, annotationMetadata, attributes);將要創建接口的代理對象的信息放在registry裏面。
- 接下來,在ReflectiveFeign的newInstance()方法中創建對應的代理對象,可以從中看到我們熟悉的代碼:
- 但是這次的InvocationHandler是已經被提前實現的靜態內部類:
- InvocationHandler類中的invoke()方法是代理的關鍵,此處相當於我們之前動態代理中自己實現的InvocationHandler匿名類:
- return dispatch.get(method).invoke(args);是真正的執行。創建一個RequestTemplate 對象
- executeAndDecode(template);繼續調用:
5. feign源碼總結
- feign通過ReflectiveFeign的newInstance()方法中的InvocationHandler handler = factory.create(target, methodToHandler)完成代理對象的創建,可以看出feign的本質就是代理對象的調用。
- 在ReflectiveFeign.FeignInvocationHandler是實現了JDK 的InvocationHandler