国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Spring源碼分析】從源碼角度去熟悉依賴注入(二)

這篇具有很好參考價(jià)值的文章主要介紹了【Spring源碼分析】從源碼角度去熟悉依賴注入(二)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

閱讀此需閱讀下面這些博客先
【Spring源碼分析】Bean的元數(shù)據(jù)和一些Spring的工具
【Spring源碼分析】BeanFactory系列接口解讀
【Spring源碼分析】執(zhí)行流程之非懶加載單例Bean的實(shí)例化邏輯
【Spring源碼分析】從源碼角度去熟悉依賴注入(一)

上篇這里簡單提一下哈,怕有些沒看的,這是連著的…:

  • 上篇是提了下生命周期的屬性注入階段,也就是 populateBean 的具體實(shí)現(xiàn);
  • 然后里面涉及到實(shí)例化后階段,和三種注入方式,Spring的BYNAME和BYTYPE還有通過MergedBeanDefinitionPostProcessor 去重定義 BeanDefinition 時(shí)的注入這倆種是簡單提了一下,然后就準(zhǔn)備去詳細(xì)分析一下使用@Autowired注解是如何注入的呢?這就涉及到 InstantiationAwareBeanPostProcessor 的實(shí)現(xiàn)類 AutowiredAnnotationBeanPostProcessor 里的具體實(shí)現(xiàn)了;
  • 然后就去簡單分析了一下是注入的,首先是去遍歷屬性和方法,看誰有 @Autowired、@Value 這倆注解,有就創(chuàng)建對(duì)應(yīng)的 InjectElement 然后進(jìn)行注入。

這篇呢主要就是去分析一下 AutowiredFieldElement 和 AutowiredMethodElement 里注入的具體實(shí)現(xiàn)。
也是對(duì)應(yīng)著下面流程圖中的 如何去尋找Bean的?

【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql

一、AutowiredFieldElement 注入分析

注入屬性,就是去找到對(duì)應(yīng)Bean,然后通過反射去賦值了,所以咱具體看看 resolveFieldValue(這上篇都有說過):
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql往里看,可以注意到其解析依賴獲取Bean的邏輯是通過 beanFactory#resolveDependency 去實(shí)現(xiàn)的,傳的參數(shù)有倆主要的就是類型轉(zhuǎn)化器和屬性描述對(duì)象(它是 AutowiredCapableBeanFactory 接口里的一個(gè)方法,即使不說,也應(yīng)該猜到,畢竟這是在屬性注入流程里出現(xiàn)的):
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql上篇說了,AutowiredAnnotationBeanPostProcessor 是有實(shí)現(xiàn) BeanFactoryAware 接口的,那么它在初始化前就會(huì)去操作把 BeanFactory 注入到它這里面,注入的是 DefaultListableBeanFactory ,然后它向上轉(zhuǎn)型成了 ConfigurableListableBeanFactory,轉(zhuǎn)不轉(zhuǎn)都一樣,ConfigurableListableBeanFactory 接口本就覆蓋了所有 BeanFactory 接口系列的功能,這前面也闡述過:
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql
那也就是說,咱接下來得分析,DefaultListableBeanFactory#resolveDependency,在分析之前得清除,這是 DefaultListableBeanFactory 下的方法實(shí)現(xiàn),而傳的參數(shù) DependencyDescriptor 也是注入點(diǎn)的子類,就是說其可以描述構(gòu)造參數(shù)、屬性、方法參數(shù),即該方法不管是注入的公共方法,包括屬性和方法(所以如果碰到關(guān)系方法的地方不要懵,比如下面的第一行)。

	@Override
	@Nullable
	public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
			@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
		// 用來獲取方法入?yún)⒚值?/span>
		descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());

		// 所需要的類型是Optional
		if (Optional.class == descriptor.getDependencyType()) {
			return createOptionalDependency(descriptor, requestingBeanName);
		}
		// 所需要的的類型是ObjectFactory,或ObjectProvider
		else if (ObjectFactory.class == descriptor.getDependencyType() ||
				ObjectProvider.class == descriptor.getDependencyType()) {
			return new DependencyObjectProvider(descriptor, requestingBeanName);
		}
		else if (javaxInjectProviderClass == descriptor.getDependencyType()) {
			return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName);
		}
		else {
			// 在屬性或set方法上使用了@Lazy注解,那么則構(gòu)造一個(gè)代理對(duì)象并返回,真正使用該代理對(duì)象時(shí)才進(jìn)行類型篩選Bean
			Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary(
					descriptor, requestingBeanName);

			if (result == null) {
				// descriptor表示某個(gè)屬性或某個(gè)set方法
				// requestingBeanName表示正在進(jìn)行依賴注入的Bean
				result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter);
			}
			return result;
		}
	}

  • 首先是獲取到參數(shù)的名字,這肯定是字節(jié)碼層面的,咱別去細(xì)究了;
  • 然后是去對(duì)類型進(jìn)行判斷,Optional、ObjectFactory、ObjectProvider、javax下的那Provider,這些俺幾乎不用,不去詳細(xì)看了,直接看else的邏輯;
  • 判斷參數(shù)上是不是加了@Lazy注解,如果加了表示該Bean注入進(jìn)行懶加載,這樣就話返回的就是一個(gè) CGLIB 的動(dòng)態(tài)代理對(duì)象。
    • 在 Mybatis 源碼分析里,咱遇到過Javassit、jdk、CGLIB 三種動(dòng)態(tài)代理,這里為什么選擇 CGLIB原因如下:它不是運(yùn)行時(shí)候用的,它是直接Spring加載的時(shí)候進(jìn)行的,所以不需要Javassit 去做,而jdk動(dòng)態(tài)代理是在接口層面的,屬性注入肯定不僅僅是類,所以毫無疑問 CGLIB 是這里最好的選擇了
  • 如果沒用 @Lazy 的話,就是正常構(gòu)造了,調(diào)用 doResolveDependency 方法。

下面有做懶加載的測試:
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql可以看見這調(diào)試的是一個(gè)代理對(duì)象,且是 CGLIB 代理:
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sqldoResolveDependency 方法是解決屬性注入的核心,咱分標(biāo)題去分析。下面看一下,AutowiredMethodElement的注入,將倆關(guān)聯(lián)起來。

二、AutowiredMethodElement注入分析

有關(guān)方法方式的注入,主要是在 resolveMethodArguments 方法中進(jìn)行:

【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql里面的實(shí)現(xiàn)邏輯就是去遍歷每一個(gè)參數(shù),然后去調(diào)用 DefaultListableBeanFactory#resolveDependency 方法獲取到對(duì)應(yīng)的Bean,然后放到數(shù)組中,最后返回。

【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql至于 resolveDependency 的實(shí)現(xiàn)邏輯,就和上面串起來了。

三、doResolveDependency 源碼分析

(吐槽一下,本來就是這部分注入流程都在這里,我分析源碼解讀算細(xì)了,但CSDN md 惡心人,昨天寫的今天打開草稿一看全沒了,我是真服了)
先給出源碼,再針對(duì)源碼各部分依次解讀:

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

		InjectionPoint previousInjectionPoint = ConstructorResolver.setCurrentInjectionPoint(descriptor);
		try {
			// 如果當(dāng)前descriptor之前做過依賴注入了,則可以直接取shortcut了,相當(dāng)于緩存
			Object shortcut = descriptor.resolveShortcut(this);
			if (shortcut != null) {
				return shortcut;
			}

			Class<?> type = descriptor.getDependencyType();
			// 獲取@Value所指定的值
			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
			if (value != null) {
				if (value instanceof String) {
					// 占位符填充(${})
					String strVal = resolveEmbeddedValue((String) value);
					BeanDefinition bd = (beanName != null && containsBean(beanName) ?
							getMergedBeanDefinition(beanName) : null);

					// 解析Spring表達(dá)式(#{})
					value = evaluateBeanDefinitionString(strVal, bd);
				}
				// 將value轉(zhuǎn)化為descriptor所對(duì)應(yīng)的類型
				TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
				try {
					return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
				}
				catch (UnsupportedOperationException ex) {
					// A custom TypeConverter which does not support TypeDescriptor resolution...
					return (descriptor.getField() != null ?
							converter.convertIfNecessary(value, type, descriptor.getField()) :
							converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
				}
			}

			// 如果descriptor所對(duì)應(yīng)的類型是數(shù)組、Map這些,就將descriptor對(duì)應(yīng)的類型所匹配的所有bean方法,不用進(jìn)一步做篩選了
			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}

			// 找到所有Bean,key是beanName, value有可能是bean對(duì)象,有可能是beanClass
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
			if (matchingBeans.isEmpty()) {
				// required為true,拋異常
				// 找不到對(duì)應(yīng)的Bean,但是 required 又是 true,就會(huì)拋出異常,@Autowired 的 required 默認(rèn)是 true 的
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				return null;
			}

			String autowiredBeanName;
			Object instanceCandidate;

			if (matchingBeans.size() > 1) {
				// 根據(jù)類型找到了多個(gè)Bean,進(jìn)一步篩選出某一個(gè), @Primary-->優(yōu)先級(jí)最高--->name
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
						return descriptor.resolveNotUnique(descriptor.getResolvableType(), 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();
			}

			// 記錄匹配過的beanName
			if (autowiredBeanNames != null) {
				autowiredBeanNames.add(autowiredBeanName);
			}
			// 有可能篩選出來的是某個(gè)bean的類型,此處就進(jìn)行實(shí)例化,調(diào)用getBean
			if (instanceCandidate instanceof Class) {
				instanceCandidate = descriptor.resolveCandidate(autowiredBeanName, type, this);
			}
			Object result = instanceCandidate;
			if (result instanceof NullBean) {
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				result = null;
			}
			if (!ClassUtils.isAssignableValue(type, result)) {
				throw new BeanNotOfRequiredTypeException(autowiredBeanName, type, instanceCandidate.getClass());
			}
			return result;
		}
		finally {
			ConstructorResolver.setCurrentInjectionPoint(previousInjectionPoint);
		}
	}

1. @Value 注解解析

在判定字段和方法是否為注入點(diǎn)時(shí),除了判定 @Autowired 注解還有就是 @Value 注解。而這里就是對(duì) @Value 注解進(jìn)行解析:

			Class<?> type = descriptor.getDependencyType();
			// 獲取@Value所指定的值
			Object value = getAutowireCandidateResolver().getSuggestedValue(descriptor);
			if (value != null) {
				if (value instanceof String) {
					// 占位符填充(${})
					String strVal = resolveEmbeddedValue((String) value);
					BeanDefinition bd = (beanName != null && containsBean(beanName) ?
							getMergedBeanDefinition(beanName) : null);

					// 解析Spring表達(dá)式(#{})
					value = evaluateBeanDefinitionString(strVal, bd);
				}
				// 將value轉(zhuǎn)化為descriptor所對(duì)應(yīng)的類型
				TypeConverter converter = (typeConverter != null ? typeConverter : getTypeConverter());
				try {
					return converter.convertIfNecessary(value, type, descriptor.getTypeDescriptor());
				}
				catch (UnsupportedOperationException ex) {
					// A custom TypeConverter which does not support TypeDescriptor resolution...
					return (descriptor.getField() != null ?
							converter.convertIfNecessary(value, type, descriptor.getField()) :
							converter.convertIfNecessary(value, type, descriptor.getMethodParameter()));
				}
			}

解析過程很簡單,就是拿到 @Value 注解中的內(nèi)容,若是 ${} 開頭就去 Environment 中去尋其結(jié)果。要是 #{} 開頭就是用 SPEL 表達(dá)式解析器去解析。
不管是從環(huán)境對(duì)象(配置文件、系統(tǒng)配置、總環(huán)境配置)中去找還是SPEL表達(dá)式解析,最后都有一個(gè)值,然后再交給轉(zhuǎn)換器進(jìn)行轉(zhuǎn)換得到結(jié)果后返回。

測試 ${} 和 #{}

編寫對(duì)應(yīng)配置:
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql引入配置:
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql
測試:
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql

2. resolveMultipleBeans 篩選特殊類型(處理多Bean)

			// 如果descriptor所對(duì)應(yīng)的類型是數(shù)組、Map這些,就將descriptor對(duì)應(yīng)的類型所匹配的所有bean方法,不用進(jìn)一步做篩選了
			Object multipleBeans = resolveMultipleBeans(descriptor, beanName, autowiredBeanNames, typeConverter);
			if (multipleBeans != null) {
				return multipleBeans;
			}

resolveMultipleBeans 方法對(duì) Stream、數(shù)組、Collection、Map 這三種情況進(jìn)行了處理。
其實(shí)處理方式大致都一樣,這里隨便抽一種類型進(jìn)行解釋,其他的你們能懂。
Map 的處理方式如下:
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql

  • 主要就是去找到 Map 上對(duì)應(yīng)的泛型類型;
  • 然后通過Value泛型的類型去調(diào)用 findAutowireCandidates 方法去根據(jù)類型找對(duì)應(yīng)的Beans,返回的是一個(gè) Map<String,Object> 其中key 是 beanName,Value 是對(duì)應(yīng)的Bean。
  • 若是其他類型的話就這個(gè)Map進(jìn)行些處理,然后返回結(jié)果集就好了,這 Map 是不需要處理的,然后就直接返回了。

測試

【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql

findAutowireCandidates 方法解析

這個(gè)方法很重要,也很難,主要概括下就是通過類型去找對(duì)應(yīng)Bean的Map集合,Key 是 BeanName,Value 的話是對(duì)應(yīng)的Bean或者是對(duì)應(yīng)的Class對(duì)象。

先給出源碼的解析:

	protected Map<String, Object> findAutowireCandidates(
			@Nullable String beanName, Class<?> requiredType, DependencyDescriptor descriptor) {

		// 從BeanFactory中找出和requiredType所匹配的beanName,僅僅是beanName,這些bean不一定經(jīng)過了實(shí)例化,只有到最終確定某個(gè)Bean了,如果這個(gè)Bean還沒有實(shí)例化才會(huì)真正進(jìn)行實(shí)例化
		String[] candidateNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
				this, requiredType, true, descriptor.isEager());
		Map<String, Object> result = CollectionUtils.newLinkedHashMap(candidateNames.length);

		// 根據(jù)類型從resolvableDependencies中匹配Bean,resolvableDependencies中存放的是類型:Bean對(duì)象,比如BeanFactory.class:BeanFactory對(duì)象,在Spring啟動(dòng)時(shí)設(shè)置
		for (Map.Entry<Class<?>, Object> classObjectEntry : this.resolvableDependencies.entrySet()) {
			Class<?> autowiringType = classObjectEntry.getKey();
			if (autowiringType.isAssignableFrom(requiredType)) {
				Object autowiringValue = classObjectEntry.getValue();
				autowiringValue = AutowireUtils.resolveAutowiringValue(autowiringValue, requiredType);

				if (requiredType.isInstance(autowiringValue)) {
					result.put(ObjectUtils.identityToString(autowiringValue), autowiringValue);
					break;
				}
			}
		}


		for (String candidate : candidateNames) {
			// 如果不是自己,則判斷該candidate到底能不能用來進(jìn)行自動(dòng)注入
			if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, descriptor)) {
				addCandidateEntry(result, candidate, descriptor, requiredType);
			}
		}

		// 為空要么是真的沒有匹配的,要么是匹配的自己
		if (result.isEmpty()) {
			// 需要匹配的類型是不是Map、數(shù)組之類的
			boolean multiple = indicatesMultipleBeans(requiredType);
			// Consider fallback matches if the first pass failed to find anything...
			DependencyDescriptor fallbackDescriptor = descriptor.forFallbackMatch();
			for (String candidate : candidateNames) {
				if (!isSelfReference(beanName, candidate) && isAutowireCandidate(candidate, fallbackDescriptor) &&
						(!multiple || getAutowireCandidateResolver().hasQualifier(descriptor))) {
					addCandidateEntry(result, candidate, descriptor, requiredType);
				}
			}

			// 匹配的是自己,被自己添加到result中
			if (result.isEmpty() && !multiple) {
				// Consider self references as a final pass...
				// but in the case of a dependency collection, not the very same bean itself.
				for (String candidate : candidateNames) {
					if (isSelfReference(beanName, candidate) &&
							(!(descriptor instanceof MultiElementDescriptor) || !beanName.equals(candidate)) &&
							isAutowireCandidate(candidate, fallbackDescriptor)) {
						addCandidateEntry(result, candidate, descriptor, requiredType);
					}
				}
			}
		}
		return result;
	}

咱先對(duì)整體的流程進(jìn)行個(gè)概述:

  • BeanFactoryUtils.beanNamesForTypeIncludingAncestors 是去根據(jù)類型去找到對(duì)應(yīng)的 beanNames,這個(gè)是真正的根據(jù)類型去找。內(nèi)部實(shí)現(xiàn)概述起來不難,就是去遍歷所有的beanNames,如果單例池中有就拿bean出來,沒有就去找對(duì)應(yīng)的beanDefinition,那里面在掃描過程中有把Class實(shí)體存進(jìn)去,那么直接 instanceOf 就知道合不合要求了。

    • 【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql
  • 下一步就是去遍歷Spring啟動(dòng)的時(shí)候會(huì)放入寫實(shí)體放到 resolvableDependencies 下,就是這些類型的話也是可以被注入的,我所說的有如下幾個(gè):

    • beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
      beanFactory.registerResolvableDependency(ResourceLoader.class, this);
      beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
      beanFactory.registerResolvableDependency(ApplicationContext.class, this);
  • 對(duì)注入的不是自己再度進(jìn)行篩選,通過的 isAutowireCandidate 方法,這里用了責(zé)任鏈的設(shè)計(jì)模式,下面會(huì)再度概述這點(diǎn)。

  • 如果篩選到最后沒一個(gè)符合的,就會(huì)去判斷是否引用的自己,是的話放入返回的結(jié)果集中。

isAutowireCandidate 源碼分析

這個(gè)是 findAutowireCandidates 中的第三點(diǎn),前倆點(diǎn)主要是找可以注入的實(shí)體,只有第三點(diǎn)是會(huì)進(jìn)行再次篩選。

isAutowireCandidate 這個(gè)方法是一個(gè)重載方法,只有它返回為true,才會(huì)嘗試放入返回結(jié)果集中,我們直接看最核心的這個(gè)方法。
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql看來看去最后是以 AutowireCandidateResolver#isAutowireCandidate 為返回結(jié)果:

在分析之前,還是得看一下這個(gè)關(guān)系圖;
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql源碼中所使用的 AutowireCandidatesResolver 實(shí)體就是 QualifierAnnotationAutowireCandidateResolver 實(shí)體對(duì)象,接下來咱就看看它的 #isAutowireCandidate 的實(shí)現(xiàn):
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql它首先是去父類的篩選,若父類篩選不通過的話就直接返回FALSE了,不會(huì)執(zhí)行if里的代碼。
而 if 里面的代碼就是對(duì) @Qualifier 注解(限定符)的篩選,若原實(shí)體和注入字段上有@Qualifier注解就去比對(duì)里面的Value值

父類 GenericTypeAwareAutowireCandidateResolver 解析也是一樣,先交給父類,然后再嘗試自己執(zhí)行,這個(gè)是去解析泛型的,一點(diǎn)復(fù)雜,不解析了。

【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql再往上的話就是 SimpleAutowireCandidateResolver 去解析了,就是判斷BeanDefinition中的autowireCandidate是不是為true,默認(rèn)是true的,允許注入:

【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql這是典型的責(zé)任鏈設(shè)計(jì)模式,其中執(zhí)行流程是 SimpleAutowireCandidateResolver -》GenericTypeAwareAutowireCandidateResolver -》QualifierAnnotationAutowireCandidateResolver,沒前一步都影響后續(xù)的執(zhí)行,相比過濾器那種它只是沒有前置處理,也不需要。

測試

對(duì)上面的三種過濾形式進(jìn)行個(gè)簡單測試好理解:

SimpleAutowireCandidateResolver 主要是去判斷 autowireCandidate 是不是為true。
下面我把 autowireCandidate 設(shè)置為了 FALSE,那么注入肯定會(huì)報(bào)錯(cuò)的(報(bào)錯(cuò)位置應(yīng)該是在 doResolveDependency 中找不到對(duì)應(yīng)注入實(shí)體,但是 required 又是true):
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql然后就是 GenericTypeAwareAutowireCandidateResolver 解析器去對(duì)泛型的篩選,如下所示:

public class BaseService<O, S> {

	@Autowired
	protected O o;

	@Autowired
	protected S s;

}

【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sqlBaseService 中定義了泛型,然后 UserService 繼承了 BaseService 然后指定了泛型類型,這里就是對(duì)這個(gè)泛型類型進(jìn)行篩選。由于這里是泛型,在起初 BeanFactoryUtils.beanNamesForTypeIncludingAncestors 得到的結(jié)果是所有的 beanNames,而這里就可以得到泛型類型的真正篩選。

打斷點(diǎn)測試:
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql可以發(fā)現(xiàn)要注入的類型是 Object,而篩選出來的結(jié)果是所有的 beanName
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql
而那流程執(zhí)行結(jié)束看結(jié)果:
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql
最后輸出:
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sqlQualifierAnnotationAutowireCandidateResolver 去解析@Qualifier我覺得開發(fā)過的對(duì)這個(gè)應(yīng)該都不陌生的。
無非就是去標(biāo)志一下,最后注入的時(shí)候需要比對(duì)一下:
比如下面提供幾種負(fù)載均衡策略實(shí)體,然后通過注解自由注入例子:

@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier("random")
public @interface Random {
}
@Target({ElementType.TYPE, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Qualifier("roundRobin")
public @interface RoundRobin {
}
public interface LoadBalance {
String select();
}
@Component
@Random
public class RandomStrategy implements LoadBalance {
@Override
public String select() {
return null;
}
}
@Component
@RoundRobin
public class RoundRobinStrategy implements LoadBalance {
@Override
public String select() {
return null;
}
}

【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql無非就是前后限定符的比對(duì)。

3. 根據(jù)類型找Bean沒找著且required=true

			// 找到所有Bean,key是beanName, value有可能是bean對(duì)象,有可能是beanClass
			Map<String, Object> matchingBeans = findAutowireCandidates(beanName, type, descriptor);
			if (matchingBeans.isEmpty()) {
				// required為true,拋異常
				// 找不到對(duì)應(yīng)的Bean,但是 required 又是 true,就會(huì)拋出異常,@Autowired 的 required 默認(rèn)是 true 的
				if (isRequired(descriptor)) {
					raiseNoMatchingBeanFound(type, descriptor.getResolvableType(), descriptor);
				}
				return null;
			}

通過 findAutowireCandidates 要是沒有找到結(jié)果集的話,就說明沒有匹配的 Bean,那么這時(shí)required又是true,默認(rèn)就是true,那么這時(shí)會(huì)拋出異常。

4. 尋找唯一Bean(普通注入)

現(xiàn)在就是我們最常見的注入了,就是普通的注入,前面奇奇怪怪的都被篩選光了。

			String autowiredBeanName;
			Object instanceCandidate;

			if (matchingBeans.size() > 1) {
				// 根據(jù)類型找到了多個(gè)Bean,進(jìn)一步篩選出某一個(gè), @Primary-->優(yōu)先級(jí)最高--->name
				autowiredBeanName = determineAutowireCandidate(matchingBeans, descriptor);
				if (autowiredBeanName == null) {
					if (isRequired(descriptor) || !indicatesMultipleBeans(type)) {
						return descriptor.resolveNotUnique(descriptor.getResolvableType(), 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();
			}

這里的話會(huì)先進(jìn)行判斷,若 findAutowireCandidates 返回的結(jié)果集是多個(gè)那就進(jìn)行再處理,若是一個(gè)則沒啥好說的,直接返回到時(shí)候反射賦值就是了。那咱就看看它多個(gè)的情況下又會(huì)做哪些處理吧,主要是在 determineAutowireCandidate 方法中。

這個(gè)方法實(shí)現(xiàn)不難,主要就是三層篩選,先@Primary,再@Priority,前倆者都沒的話就根據(jù)名字了。

	@Nullable
	protected String determineAutowireCandidate(Map<String, Object> candidates, DependencyDescriptor descriptor) {
		Class<?> requiredType = descriptor.getDependencyType();
		// candidates表示根據(jù)類型所找到的多個(gè)Bean,判斷這些Bean中是否有一個(gè)是@Primary的
		String primaryCandidate = determinePrimaryCandidate(candidates, requiredType);
		if (primaryCandidate != null) {
			return primaryCandidate;
		}

		// 取優(yōu)先級(jí)最高的Bean
		String priorityCandidate = determineHighestPriorityCandidate(candidates, requiredType);
		if (priorityCandidate != null) {
			return priorityCandidate;
		}

		// Fallback
		// 匹配descriptor的名字,要么是字段的名字,要么是set方法入?yún)⒌拿?/span>
		for (Map.Entry<String, Object> entry : candidates.entrySet()) {
			String candidateName = entry.getKey();
			Object beanInstance = entry.getValue();

			// resolvableDependencies記錄了某個(gè)類型對(duì)應(yīng)某個(gè)Bean,啟動(dòng)Spring時(shí)會(huì)進(jìn)行設(shè)置,比如BeanFactory.class對(duì)應(yīng)BeanFactory實(shí)例
			// 注意:如果是Spring自己的byType,descriptor.getDependencyName()將返回空,只有是@Autowired才會(huì)方法屬性名或方法參數(shù)名
			if ((beanInstance != null && this.resolvableDependencies.containsValue(beanInstance)) ||
					matchesBeanName(candidateName, descriptor.getDependencyName())) {
				return candidateName;
			}
		}
		return null;
	}

@Priority 注解的篩選要看一下,是以值越小優(yōu)先級(jí)越高來判斷的:
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql
其它就沒啥好說的。

四、總結(jié)

這簡單做個(gè)小結(jié)吧,注意這里是和上一節(jié)是一起的:

  • 這個(gè)屬性注入呢考慮的是去遍歷 InstantiationAwareBeanPostProcessor 中的屬性注入方法調(diào)用,其中有個(gè) AutowiredAnnotationBeanPostProcessor 就是我們所分析的。
  • 首先呢就是去遍歷屬性遍歷方法尋找注入點(diǎn),找到后封裝成一個(gè)注入點(diǎn)實(shí)體存進(jìn)集合中;
  • 遍歷這個(gè)集合依次進(jìn)行注入,要是方法的話就參數(shù)遍歷個(gè)遍去調(diào)用 doResolverDependency 方法獲取要注入的bean,最后合一起反射調(diào)用方法就是了,屬性的話,更簡單,獲取后反射直接賦值。
  • doResolveDependency邏輯:
    • 先進(jìn)行 @Value 注解的注入;
    • 篩選Map、Stream、Collection、數(shù)組這特殊類型;
    • findAutowireCandidates 去根據(jù)類型篩選Bean,其中篩選有 autowireCandidate 需要為 true,篩選泛型類型,篩選 @Qualifier 限定符匹配的。
    • 若有多Bean需要注入還需要進(jìn)行篩選:
      • @Primary
      • @Priority(注意這里是值越小優(yōu)先級(jí)越高,且值不能一樣,不然拋異常的)
      • 屬性名或者說是參數(shù)名和 beanName 匹配一個(gè)出來。
  • 反射調(diào)用/反射賦值(完成依賴注入!?。。?/li>

篩選6步記住:@Value ---- autowireCandidate 元數(shù)據(jù)屬性要為 true ----- @Qualifier 限定符若有需匹配 ------- 多Bean的話 @Primary --------@Priority ------屬性名或者參數(shù)名匹配

下一篇的話把 @Resource 注解注入源碼也分析一下,其實(shí)可以猜到,也得通過 InstantiationAwareBeanPostProcessor 中的屬性注入方法的遍歷。

搞個(gè)流程圖就像如下步驟一樣:
【Spring源碼分析】從源碼角度去熟悉依賴注入(二),Java源碼分析,spring,數(shù)據(jù)庫,sql文章來源地址http://www.zghlxwxcb.cn/news/detail-824369.html

到了這里,關(guān)于【Spring源碼分析】從源碼角度去熟悉依賴注入(二)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • Spring-1-深入理解Spring XML中的依賴注入(DI):簡化Java應(yīng)用程序開發(fā)

    Spring-1-深入理解Spring XML中的依賴注入(DI):簡化Java應(yīng)用程序開發(fā)

    前兩篇文章我們介紹了什么是Spring,以及Spring的一些核心概念,并且快速快發(fā)一個(gè)Spring項(xiàng)目,以及詳細(xì)講解IOC,今天詳細(xì)介紹一些DI(依賴注入) 能夠配置setter方式注入屬性值 能夠配置構(gòu)造方式注入屬性值 能夠理解什么是自動(dòng)裝配 思考:向一個(gè)類中傳遞數(shù)據(jù)的方式有幾種?(給類

    2024年02月13日
    瀏覽(27)
  • Java Spring IoC&DI :探索Java Spring中控制反轉(zhuǎn)和依賴注入的威力,增強(qiáng)靈活性和可維護(hù)性

    Java Spring IoC&DI :探索Java Spring中控制反轉(zhuǎn)和依賴注入的威力,增強(qiáng)靈活性和可維護(hù)性

    ?? 博客主頁:從零開始的-CodeNinja之路 ? 收錄文章:Java Spring IoCDI :探索Java Spring中控制反轉(zhuǎn)和依賴注入的威力,增強(qiáng)靈活性和可維護(hù)性 ??歡迎大家點(diǎn)贊??評(píng)論??收藏?文章 我們一下要學(xué)習(xí)的內(nèi)容都是為了實(shí)現(xiàn)?內(nèi)聚低耦合來進(jìn)行的 軟件設(shè)計(jì)原則:?內(nèi)聚低耦合. ?內(nèi)聚指

    2024年04月15日
    瀏覽(23)
  • Spring 02 -Spring依賴注入+Spring注解開發(fā)

    依賴注入:在Spring創(chuàng)建對(duì)象的同時(shí),為其屬性賦值,稱之為依賴注入。 創(chuàng)建對(duì)象時(shí),Spring工廠會(huì)通過Set方法為對(duì)象的屬性賦值。 范例:定義一個(gè)Bean類型 屬性注入 范例:定義一個(gè)Bean類型 提供構(gòu)造方法 構(gòu)造方法注入 復(fù)雜類型指的是:list、set、map、array、properties等類型 定義

    2023年04月09日
    瀏覽(27)
  • Spring面試整理-Spring的依賴注入

    Spring框架的依賴注入(DI)是其核心功能之一,它允許對(duì)象定義它們依賴的其他對(duì)象,而不是自己創(chuàng)建或查找它們。這種機(jī)制促進(jìn)了松耦合和更容易的測試。 依賴注入是一種設(shè)計(jì)模式,其中一個(gè)對(duì)象或方法提供另一個(gè)對(duì)象的依賴關(guān)系。在Spring中,這些依賴通常是服務(wù)、配置值

    2024年01月19日
    瀏覽(23)
  • Spring IOC:詳解【依賴注入數(shù)值問題 & 依賴注入方式】

    Spring IOC:詳解【依賴注入數(shù)值問題 & 依賴注入方式】

    編譯軟件:IntelliJ IDEA 2019.2.4 x64 操作系統(tǒng):win10 x64 位 家庭版 Maven版本:apache-maven-3.6.3 Mybatis版本:3.5.6 spring版本:5.3.1 第一章:初識(shí)Spring:如何在Maven工程上搭建Spring框架? 第二章:Spring IOC:IOC在Spring底層中如何實(shí)現(xiàn)? 第三章:Spring IOC:詳解【依賴注入數(shù)值問題 依賴注入

    2024年02月04日
    瀏覽(17)
  • spring——依賴注入原理及注入方式

    ??1.依賴注入(Dependency Injection,DI) 是一種設(shè)計(jì)模式和編程技術(shù),其原理是將對(duì)象的依賴關(guān)系由外部容器來管理和注入。它的目的是解耦組件之間的依賴關(guān)系,提高代碼的靈活性、可維護(hù)性和可測試性。 ??2.依賴注入的原理 是通過在對(duì)象的構(gòu)造函數(shù)、屬性或方法中注入所依

    2024年02月08日
    瀏覽(27)
  • Spring DI簡介及依賴注入方式和依賴注入類型

    Spring DI簡介及依賴注入方式和依賴注入類型

    目錄 一、什么是依賴注入 二、依賴注入方式 1. Setter注入 2. 構(gòu)造方法注入 3. 自動(dòng)注入? 三、依賴注入類型 1. 注入bean類型 2. 注入基本數(shù)據(jù)類型 3. 注入List集合 4. 注入Set集合 5. 注入Map集合 6. 注入Properties對(duì)象 往期專欄文章相關(guān)導(dǎo)讀? 1. Maven系列專欄文章 2. Mybatis系列專欄文章

    2024年02月02日
    瀏覽(22)
  • Spring 依賴注入詳解

    目錄 1、基于構(gòu)造器的依賴注入 2、基于 Setter 方法的依賴注入 3、使用構(gòu)造器注入還是 setter 方法注入? 4、依賴注入解析的過程 5、依賴注入的相關(guān)示例 // 依賴關(guān)系,指的就是對(duì)象之間的相互協(xié)作關(guān)系 ????????依賴注入(DI)是一個(gè)過程,在這個(gè)過程中,對(duì)象僅通過構(gòu)造函

    2024年02月06日
    瀏覽(15)
  • 4、Spring之依賴注入

    4、Spring之依賴注入

    依賴注入就是對(duì)類的屬性進(jìn)行賦值 創(chuàng)建名為spring_ioc_xml的新module,過程參考3.1節(jié) 注意:constructor-arg標(biāo)簽的數(shù)量,必須和某一個(gè)構(gòu)造器方法的參數(shù)數(shù)量一致 4.4.1.1、配置bean 注意:該property name=\\\"sex\\\" value=\\\"null\\\"寫法,實(shí)際為sex所賦的值是字符串null 4.4.1.2、測試 由控制臺(tái)日志可知,

    2024年02月14日
    瀏覽(21)
  • Spring 的依賴注入

    Spring 的依賴注入

    @ 目錄 Spring 的依賴注入 每博一文案 1. 依賴注入 1.1 構(gòu)造注入 1.1.1 通過參數(shù)名進(jìn)行構(gòu)造注入 1.1.2 通過參數(shù)的下標(biāo),進(jìn)行構(gòu)造注入 1.1.3 不指定參數(shù)下標(biāo),不指定參數(shù)名字,通過自動(dòng)裝配的方式 1.2 set 注入 2. set注入的各種方式詳解 2.1 set 注入外部Bean 2.2 set 注入內(nèi)部Bean 2.3 set 注

    2024年02月16日
    瀏覽(20)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包