【二十二】Spring filed上使用@AutoWired註解,依賴注入源碼分析

一、簡介

不清楚實例化bean、填充屬性、初始化bean的順序、做的事、執行了哪些擴展器的請看我以前寫的這篇【十八】Spring IOC 總結之getBean主流程和各個擴展點總結

測試代碼的注入方式是:直接在成員變量上用@AutoWired註解

先說重點

@Autowired在成員變量上的依賴注入是AutowiredAnnotationBeanPostProcessor來完成的

AutowiredAnnotationBeanPostProcessor處理依賴注入的整個流程概況來說就是下面三個最重要的東西來做的:

1.它實現了MergedBeanDefinitionPostProcessor,主要用到方法postProcessMergedBeanDefinition。該方法在實例化完成後調用。

該方法主要做的是:解析@Autowire註解生成注入元數據injectionMetadata。

解析出該類哪些filed和filedmethod需要依賴注入,然後放入injectionMetadataCache緩存中,待後面填充階段的postProcessPropertyValues方法使用。

2.它繼承了InstantiationAwareBeanPostProcessorAdapter,主要用到方法postProcessPropertyValues。該方法在填充階段調用。

它根據前面解析出來的injectionMetadata來做真正的依賴注入。

3.它有個map是 Map<String, InjectionMetadata> injectionMetadataCache。key是哪個bean裏面有成員需要依賴注入,這個例子中Key就是testController。value是InjectionMetadata,它保存的是該類哪些字段需要依賴注入。

二、AutowiredAnnotationBeanPostProcessor#postProcessMergedBeanDefinition方法

在bean實例化後,例子中即是testController(它裏面需要注入成員變量testService)實例化後,進入填充階段前,會調用該方法

源碼:

	@Override
	public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition, Class<?> beanType, String beanName) {
		if (beanType != null) {
			InjectionMetadata metadata = findAutowiringMetadata(beanName, beanType, null);
			metadata.checkConfigMembers(beanDefinition);
		}
	}

做了兩件事

1.搜索該Bean內@Autowired註解的信息,生成InjectionMetadata需要依賴注入的元數據信息

2. 檢查配置成員

2.1.findAutowiringMetadata方法

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, PropertyValues pvs) {
		// Fall back to class name as cache key, for backwards compatibility with custom callers.
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());

        //// 緩存中根據beanNmae獲取該bean的InjectionMetadata
		// Quick check on the concurrent map first, with minimal locking.
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);

       //如果metadata爲null或者metadata!=clazz
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
			synchronized (this.injectionMetadataCache) {
				metadata = this.injectionMetadataCache.get(cacheKey);


                //如果metadata爲null或者metadata!=clazz
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
					if (metadata != null) {
						metadata.clear(pvs);
					}
					try {
						metadata = buildAutowiringMetadata(clazz);

                        //放入緩存
						this.injectionMetadataCache.put(cacheKey, metadata);
					}
					catch (NoClassDefFoundError err) {
						throw new IllegalStateException("Failed to introspect bean class [" + clazz.getName() +
								"] for autowiring metadata: could not find class that it depends on", err);
					}
				}
			}
		}
		return metadata;
	}

做了2件事:

1.以testController(它裏面需要注入成員變量testService)爲KEY,在injectionMetadataCache找InjectionMetadata

那麼,很不幸,第一次是找不到的。找到了就直接返回了

2.找不到那就要自己創建InjectionMetadata了,然後再放入injectionMetadataCache中。自己創建對應的方法就是源碼裏面的buildAutowiringMetadata方法

這裏用了個雙重鎖機制。

2.1.1 buildAutowiringMetadata方法

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
		LinkedList<InjectionMetadata.InjectedElement> elements = new LinkedList<InjectionMetadata.InjectedElement>();
		Class<?> targetClass = clazz;

		do {
			final LinkedList<InjectionMetadata.InjectedElement> currElements =
					new LinkedList<InjectionMetadata.InjectedElement>();

           ////遍歷這個類中的所有filed
			ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() {
				@Override
				public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException {

                    //獲取filed是否帶了@AutoWire標籤
					AnnotationAttributes ann = findAutowiredAnnotation(field);
					if (ann != null) {

                         //過濾掉static的filed
						if (Modifier.isStatic(field.getModifiers())) {
							if (logger.isWarnEnabled()) {
								logger.warn("Autowired annotation is not supported on static fields: " + field);
							}
							return;
						}

                        /這裏就取了Autowired的一個required屬性,這個屬性的作用是
                    //如果這個是false就表明在自動裝配的時候沒有發現又對應的實例
                    //就跳過去,如果是true沒有發現有與之匹配的就會拋出個異常,僅此而已
						boolean required = determineRequiredStatus(ann);
						currElements.add(new AutowiredFieldElement(field, required));
					}
				}
			});


            //遍歷這個類中的所有filedmethiod
			ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() {
				@Override
				public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException {


                     /**
                 * 這裏獲取一個橋接的方法對象
                 * 1,遍歷class裏面所有的method方法,findBridgedMethod方法會獲取method方法的聲明的類,
                 * 並且將該類下面所有的方法形成數組,然後遍歷數組跟method比較,如果方法不同,但是方法的
                 * 名稱和參數數量相同,則視爲橋接方法返回
                 */
					Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);

                   //如果橋接方法和method不同,則直接返回
					if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
						return;
					}

                   //獲取method是否帶了@AutoWire標籤
					AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod);
					if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {

                        //同樣過濾靜態方法
						if (Modifier.isStatic(method.getModifiers())) {
							if (logger.isWarnEnabled()) {
								logger.warn("Autowired annotation is not supported on static methods: " + method);
							}
							return;
						}

                        //參數數量0也過濾,注入set參數
						if (method.getParameterTypes().length == 0) {
							if (logger.isWarnEnabled()) {
								logger.warn("Autowired annotation should only be used on methods with parameters: " +
										method);
							}
						}
						boolean required = determineRequiredStatus(ann);
						PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
						currElements.add(new AutowiredMethodElement(method, required, pd));
					}
				}
			});

			elements.addAll(0, currElements);

            //找到該類的父類並且繼續
			targetClass = targetClass.getSuperclass();
		}
		while (targetClass != null && targetClass != Object.class);

		return new InjectionMetadata(clazz, elements);
	}

做了4件事:

1.遍歷這個類所有的Filed

獲取帶了@Autowire註解的filed,過濾掉static的filed,解析這些@Autowire是否爲requird

2.便利這個類所有的filedmethod,找到哪些方法裏面用了需要依賴注入的bean的,找到橋接方法。

如果橋接方法和method不同則直接返回。

找到哪些方法有@Autowire標籤,過來靜態方法,過濾參數數量爲0的方法,注入set參數。

3.找到該類的父類繼續前兩步操作。

4.返回InjectionMetadata。

三、AutowiredAnnotationBeanPostProcessor#postProcessPropertyValues

源碼:

	@Override
	public PropertyValues postProcessPropertyValues(
			PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeanCreationException {

        //從緩存中得到該類需要依賴注入的元數據
		InjectionMetadata metadata = findAutowiringMetadata(beanName, bean.getClass(), pvs);
		try {

            //執行依賴注入
			metadata.inject(bean, beanName, pvs);
		}
		catch (BeanCreationException ex) {
			throw ex;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", ex);
		}
		return pvs;
	}

做了2件事:

1.從該類中得到需要依賴注入的元數據

2.調用metadata.inject方法執行依賴注入

3.1 metadata.inject方法執行依賴注入

	public void inject(Object target, String beanName, PropertyValues pvs) throws Throwable {
		Collection<InjectedElement> elementsToIterate =
				(this.checkedElements != null ? this.checkedElements : this.injectedElements);
		if (!elementsToIterate.isEmpty()) {
			boolean debug = logger.isDebugEnabled();
			for (InjectedElement element : elementsToIterate) {
				if (debug) {
					logger.debug("Processing injected element of bean '" + beanName + "': " + element);
				}
				element.inject(target, beanName, pvs);
			}
		}
	}

循環調用AutowiredAnnotationBeanPostProcessor#inject進行依賴注入

@Override
		protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable {
			Field field = (Field) this.member;
			Object value;
			if (this.cached) {
				value = resolvedCachedArgument(beanName, this.cachedFieldValue);
			}
			else {
				DependencyDescriptor desc = new DependencyDescriptor(field, this.required);
				desc.setContainingClass(bean.getClass());
				Set<String> autowiredBeanNames = new LinkedHashSet<String>(1);
				TypeConverter typeConverter = beanFactory.getTypeConverter();
				try {
					value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);
				}
				catch (BeansException ex) {
					throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex);
				}
				synchronized (this) {
					if (!this.cached) {
						if (value != null || this.required) {
							this.cachedFieldValue = desc;
							registerDependentBeans(beanName, autowiredBeanNames);
							if (autowiredBeanNames.size() == 1) {
								String autowiredBeanName = autowiredBeanNames.iterator().next();
								if (beanFactory.containsBean(autowiredBeanName)) {
									if (beanFactory.isTypeMatch(autowiredBeanName, field.getType())) {
										this.cachedFieldValue = new ShortcutDependencyDescriptor(
												desc, autowiredBeanName, field.getType());
									}
								}
							}
						}
						else {
							this.cachedFieldValue = null;
						}
						this.cached = true;
					}
				}
			}
			if (value != null) {

                //通過反射爲屬性賦值
				ReflectionUtils.makeAccessible(field);
				field.set(bean, value);
			}
		}
	}

做了3件事:

1.解析依賴DefaultListableBeanFactory#beanFactory.resolveDependency

其實主要就是找到依賴。這裏後面有空詳細介紹,趕着出門買菜

2.註冊依賴registerDependentBeans

實際上就是寫入DefaultListableBeanFactory類的兩個MAP中

dependentBeanMap,key是例子中的testServiceImpl,value數組是哪些bean依賴了它,這裏的value數組中就只有testController

dependenciesForBeanMap,key是例子中的testController,value數組是testController依賴了哪些bean,這裏的value數組就只有testServiceImpl

3.通過反射爲屬性賦值

3.1.1  DefaultListableBeanFactory#beanFactory.resolveDependency

 源碼:

@Override
	public Object resolveDependency(DependencyDescriptor descriptor, String requestingBeanName,
			Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {

        // ParameterNameDiscovery用於解析方法參數名稱
		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());

         // 1. Optional<T>
		if (javaUtilOptionalClass == descriptor.getDependencyType()) {
			return new OptionalDependencyFactory().createOptionalDependency(descriptor, requestingBeanName);
		}

        // 2. ObjectFactory<T>、ObjectProvider<T>
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}

        // 3. javax.inject.Provider<T>
		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new Jsr330ProviderFactory().createDependencyProvider(descriptor, requestingBeanName);
		}
		else {

            // 4. @Lazy
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);

             // 5. 正常情況
			if (result == null) {
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}

做了2件事:

1.初始參數名稱發現

2.根據各種不同的依賴類型( Optional、延遲注入、懶加載)解析依賴並返回。

本場就就是走的最後的doResolvDependency

doResolvDependency源碼:

public Object doResolveDependency(DependencyDescriptor descriptor, String beanName,
			Set<String> autowiredBeanNames, TypeConverter typeConverter) throws BeansException {

		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {

            // 1. 快速查找,根據名稱查找。AutowiredAnnotationBeanPostProcessor用到
			Object shortcut = descriptor.resolveShortcut(this);
			if (shortcut != null) {
				return shortcut;
			}

            // 2. 注入指定值,QualifierAnnotationAutowireCandidateResolver解析@Value會用到
			Class<?> type = descriptor.getDependencyType();
			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
			if (value != null) {
				if (value instanceof String) {

                    // 2.1 佔位符解析
					String strVal = resolveEmbeddedValue((String) value);
					BeanDefinition bd = (beanName != null && containsBean(beanName) ? getMergedBeanDefinition(beanName) : null);

                    // 2.2 Spring EL 表達式
					value = evaluateBeanDefinitionString(strVal, bd);
				}
				TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());

                // 2.3 類型轉換
				return (descriptor.getField() != null ?
						converter.convertIfNecessary(value, type, descriptor.getField()) :
						converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
			}


            // 3. 集合依賴,如 Array、List、Set、Map。內部查找依賴也是使用findAutowireCandidates
			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}

 
             // 4. 單個依賴查詢
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);

            // 4.1 沒有查找到依賴,判斷descriptor.require
			if (matchingBeans.isEmpty()) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				return null;
			}

			String autowiredBeanName;
			Object instanceCandidate;


            // 4.2 有多個,如何過濾
			if (matchingBeans.size() > 1) {

                // 4.2.1 @Primary -> @Priority -> 方法名稱或字段名稱匹配 
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);

                // 4.2.2 根據是否必須,拋出異常。注意這裏如果是集合處理,則返回null
				if (autowiredBeanName == null) {
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
						return descriptor.resolveNotUnique(type, matchingBeans);
					}
					else {
						// In case of an optional Collection/Map, silently ignore a non-unique case:
						// possibly it was meant to be an empty collection of multiple regular beans
						// (before 4.3 in particular when we didn't even look for collection beans).
						return null;
					}
				}
				instanceCandidate = matchingBeans.get(autowiredBeanName);
			}
			else {
				// We have exactly one match.
				Map.Entry<String, Object> entry = matchingBeans.entrySet().iterator().next();
				autowiredBeanName = entry.getKey();
				instanceCandidate = entry.getValue();
			}


            // 4.3 到了這,說明有且僅有命中一個
			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(autowiredBeanName);
			}

            // 4.4 descriptor.resolveCandidate實際上調用 getBean(autowiredBeanName, type)。
			return (instanceCandidate instanceof Class ?
					descriptor.resolveCandidate(autowiredBeanName, type, this) : instanceCandidate);
		}
		finally {
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
		}
	}

doResolveDependency 封裝了依賴查找的各種情況:

1)快速查找: @Autowired 註解處理場景。AutowiredAnnotationBeanPostProcessor 處理 @Autowired 註解時,如果注入的對象只有一個,會將該 bean 對應的名稱緩存起來,下次直接通過名稱查找會快很多。

2)注入指定值:@Value 註解處理場景。QualifierAnnotationAutowireCandidateResolver 處理 @Value 註解時,會讀取 @Value 對應的值進行注入。如果是 String 要經過三個過程:①佔位符處理 -> ②EL 表達式解析 -> ③類型轉換,這也是一般的處理過程,BeanDefinitionValueResolver 處理 String 對象也是這個過程。

3)集合依賴查詢:直接全部委託給 resolveMultipleBeans 方法。

4) 單個依賴查詢:先調用 findAutowireCandidates 查找容器中所有可用的依賴,如果有多個依賴,則根據規則匹配: @Primary -> @Priority -> ③方法名稱或字段名稱

而findAutowireCandidates的內部邏輯是:

1.先查找 Spring IoC 內部依賴 resolvableDependencies。

在 AbstractApplicationContext#prepareBeanFactory 方法中默認設置瞭如下內部依賴:BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext。

2.在父子容器進行類型查找:查找類型匹配的 beanNames。

循環調用beanFactory#beanNamesForType 方法根據類型查找先匹配單例實例類型(包括 Spring 託管 Bean),再匹配 BeanDefinition 的類型

這裏可以看到 Spring 依賴注入的另外兩個來源:一是 Spring 託管的外部 Bean,二是 Spring BeanDefinition。 

3.補償機制

如果依賴查找無法匹配,Spring 提供了兩種補償機制。

先使用泛型補償,不允許自身引用補償:即 fallbackDescriptor。此時如果是集合依賴,對象必須是 @Qualifier 類型。

允許泛型補償和自身引用補償:但如果是集合依賴,必須過濾自己本身,即 beanName.equals(candidate) 必須剔除。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章