springcloud feign原始碼分析(4)——來看看將@FeignClient介面構造為bean的過程以及是如何註冊到容器裡的
接著上一篇,繼續來看 registerFeignClient() 方法
這邊一看就是在構造構造一個BeanDefiniction的東西,這個東西的話,構造的過程,其實就是用了構造器模式,這個構造器模式呢,就會將@FeignClient註解的屬性以及ServiceAClient相關的東西,都放到這個BeanDefinition中去
class FeignClientsRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, BeanClassLoaderAware, EnvironmentAware { //最終應該是基於這個方法完成了掃描出來的@FeignClient相關介面的註冊 private void registerFeignClient(BeanDefinitionRegistry registry, AnnotationMetadata annotationMetadata, Map<String, Object> attributes) { String className = annotationMetadata.getClassName(); //FeignClientFactoryBean是用來建立核心的FeignClient元件的一個工廠bean //FeignClientFactoryBean在後面spring容器初始化的某個階段,根據掃描出來的資訊完成ServiceAClient的feign動態代理的構造。。。 BeanDefinitionBuilder definition = BeanDefinitionBuilder .genericBeanDefinition(FeignClientFactoryBean.class); validate(attributes); definition.addPropertyValue("url", getUrl(attributes)); definition.addPropertyValue("path", getPath(attributes)); //attributes直接是引數傳進來的,就是@FeignClient裡面的屬性,value和configuration兩個屬性 String name = getName(attributes); //name:@FeignClient(value = “ServiceA”),服務名稱 definition.addPropertyValue("name", name); definition.addPropertyValue("type", className); definition.addPropertyValue("decode404", attributes.get("decode404")); definition.addPropertyValue("fallback", attributes.get("fallback")); definition.addPropertyValue("fallbackFactory", attributes.get("fallbackFactory")); definition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE); String alias = name + "FeignClient"; //就是通過構造器模式完成了@FeignClient標註的ServiceAClient介面對應的BeanDefinition的構造的過程 // 成功構造出來了一個BeanDefinition,裡面包含了@FeignClient註解和ServicewAClient介面相關的所有資訊 AbstractBeanDefinition beanDefinition = definition.getBeanDefinition(); boolean primary = (Boolean)attributes.get("primary"); // has a default, won't be null beanDefinition.setPrimary(primary); String qualifier = getQualifier(attributes); if (StringUtils.hasText(qualifier)) { alias = qualifier; } //基於介面類名(ServiceAClient介面的類名),alias(ServiceAFeignClient),剛剛構造好的BeanDefinition, //來構造了一個BeanDefinitionHolder BeanDefinitionHolder holder = new BeanDefinitionHolder(beanDefinition, className, new String[] { alias }); //就基於BeanDefinitionRegistry和BeanDefinitionHolder,完成了BeanDefinition的註冊, //註冊的邏輯就不要看了,走的是spring-beans專案的原始碼了 BeanDefinitionReaderUtils.registerBeanDefinition(holder, registry); } }
很多疑問,BeanDefinition到底是啥???BeanDefinitionHolder到底是啥???BeanDefinitionRegistry到底是啥???
抓大放小,不要去卡這種細節。。。
這段程式碼,其實是在掃描包路徑下的@FeignClient標註的介面都有哪些??然後將@FeignClient註解的屬性和我們自定義的ServiceAClient介面的資訊封裝為了BeanDefinition,註冊到了一個所謂的BeanDefinitionRegistry的地方
大膽的推測一下,其實就是在系統剛啟動的時候,這裡就是單純的完成包的掃描,以及資訊的解析,將這些東西儲存到spring框架中去,留待後面來使用。。。
通過那張大圖的理解,下一步,其實就是應該去基於掃描出來的@FeignClient註解和ServiceAClident介面的資訊,然後去建立實現ServiceAClient介面的動態代理,feign核心的動態代理,將動態代理作為一個bean,注入給ServiceBControler,然後ServiceBController後面呼叫的都是這個feign動態代理。。。
你感覺,建立這個動態代理應該是在哪兒呢???
BeanDefinitionBuilder definition = BeanDefinitionBuilder
.genericBeanDefinition(FeignClientFactoryBean.class);
注意到了嗎?FeignClientFactoryBean,一看就是靠的是這個東西作為一個工廠,在後面spring容器初始化的某個階段,根據之前掃描出來的資訊完成ServiceAClient的feign動態代理的構造。。。
驚訝的發現,FeignClientFactoryBean中,居然儲存了@FeignClient註解的所有屬性的值!!!必須得有啊!因為要根據這些屬性的值,來完成feign動態代理的構造。。。
我們明顯就是在FeignClientFactoryBean中,發現了一大坨構造FeignClient的程式碼,所以很明顯是我們的推測是這樣子的:前面僅僅是掃描@FeignClient和介面資訊,後面其實會在FeignClientFactoryBean中,在spring容器初始化的某個過程中,呼叫這個工廠bean的某個方法,建立和獲取到ServiceAClient對應的feign動態代理,放到spring容器中去
後面ServiceBController就是直接注入剛才建立好的那個動態代理
總結:掃描@FeignClient註解的機制續 流程圖