1. 程式人生 > >springcloud feign原始碼分析(4)——來看看將@FeignClient介面構造為bean的過程以及是如何註冊到容器裡的

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註解的機制續 流程圖