最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring中的依賴注入DI源碼詳細(xì)解析

 更新時間:2023年11月30日 09:14:07   作者:啊幾  
這篇文章主要介紹了Spring中的依賴注入DI源碼詳細(xì)解析,Spring的依賴注入(Dependency Injection,DI)是Spring框架核心的一部分,它是實現(xiàn)控制反轉(zhuǎn)(Inversion of Control,IoC)的一種方式,需要的朋友可以參考下

前言

Spring的依賴注入(Dependency Injection,DI)是Spring框架核心的一部分,它是實現(xiàn)控制反轉(zhuǎn)(Inversion of Control,IoC)的一種方式。

依賴注入可以幫助我們減少代碼的耦合度,提高模塊間的獨立性和可測試性。

Spring框架的依賴注入主要發(fā)生在Spring容器初始化應(yīng)用上下文時

Spring容器的主要步驟

先說說Spring容器生命周期的一些主要步驟和依賴注入的階段:

  1. 配置階段:在這個階段,Spring容器會讀取配置文件(例如XML配置文件或者使用注解的配置類),并根據(jù)這些配置信息創(chuàng)建Bean定義。Bean定義包含了創(chuàng)建和裝配一個Bean所需要的所有信息。
  2. 實例化階段:在這個階段,Spring容器會根據(jù)Bean定義創(chuàng)建Bean實例。這通常是通過調(diào)用Bean的構(gòu)造函數(shù)或工廠方法來完成的。
  3. 依賴注入階段:在這個階段,Spring容器會將依賴注入到已經(jīng)創(chuàng)建的Bean實例中。這通常是通過調(diào)用Bean的setter方法或者通過反射直接設(shè)置字段值來完成的。這個階段也可能會觸發(fā)更多的Bean的創(chuàng)建和注入,如果被注入的Bean依賴于其他的Bean的話。
  4. 初始化階段:在這個階段,Spring容器會調(diào)用Bean的初始化方法。這通常是通過調(diào)用Bean實現(xiàn)的InitializingBean接口的afterPropertiesSet方法或者調(diào)用在配置中指定的自定義初始化方法來完成的。
  5. 使用階段:在這個階段,應(yīng)用代碼可以開始使用已經(jīng)初始化和裝配好的Bean了。
  6. 銷毀階段:在這個階段,當(dāng)應(yīng)用上下文被關(guān)閉時,Spring容器會調(diào)用Bean的銷毀方法。這通常是通過調(diào)用Bean實現(xiàn)的DisposableBean接口的destroy方法或者調(diào)用在配置中指定的自定義銷毀方法來完成的。

總的來說,Spring的依賴注入主要發(fā)生在Spring容器初始化應(yīng)用上下文的過程中,具體是在實例化階段之后,初始化階段之前的依賴注入階段。

依賴注入在Spring框架中的觸發(fā)點

先看看觸發(fā)依賴注入方法調(diào)用堆棧的流程圖:

在這里插入圖片描述

  1. AbstractApplicationContext#refresh():這個方法是整個Spring應(yīng)用上下文刷新的入口點,包括Bean的創(chuàng)建和初始化。
  2. AbstractApplicationContext#finishBeanFactoryInitialization(ConfigurableListableBeanFactory): 這個方法會預(yù)實例化所有的單例Bean。
  3. DefaultListableBeanFactory#preInstantiateSingletons(): 這個方法會遍歷所有的Bean定義,對于每個非懶加載的單例Bean,通過getBean()方法獲取Bean的實例。
  4. AbstractBeanFactory#getBean(String): 這個方法會檢查是否已經(jīng)存在一個Bean的實例,如果沒有,那么它會觸發(fā)Bean的創(chuàng)建過程。
  5. AbstractAutowireCapableBeanFactory#createBean(String, RootBeanDefinition, Object[]): 這個方法會創(chuàng)建一個新的Bean實例。
  6. AbstractAutowireCapableBeanFactory#doCreateBean(String, RootBeanDefinition, Object[]): 這個方法會創(chuàng)建一個新的Bean實例,填充Bean的屬性(也就是依賴注入),并調(diào)用Bean的初始化方法。
  7. AbstractAutowireCapableBeanFactory#populateBean(String, RootBeanDefinition, BeanWrapper): 這個方法會進行依賴注入,它會遍歷Bean的所有屬性,對于每個屬性,如果它有一個匹配的Bean定義或者已存在的Bean實例,那么這個Bean會被注入到屬性中。

源碼解析

下面是依賴注入的主要代碼

protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
		if (bw == null) {
			if (mbd.hasPropertyValues()) {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
			}
			else {
				// Skip property population phase for null instance.
				return;
			}
		}
		// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
		// state of the bean before properties are set. This can be used, for example,
		// to support styles of field injection.
		// 實例化之后,屬性設(shè)置之前
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
					return;
				}
			}
		}
		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			// MutablePropertyValues是PropertyValues具體的實現(xiàn)類
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			// Add property values based on autowire by name if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			// Add property values based on autowire by type if applicable.
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}
		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				// 這里會調(diào)用AutowiredAnnotationBeanPostProcessor的postProcessProperties()方法,會直接給對象中的屬性賦值
				// AutowiredAnnotationBeanPostProcessor內(nèi)部并不會處理pvs,直接返回了
				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
					pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return;
					}
				}
				pvs = pvsToUse;
			}
		}
		if (needsDepCheck) {
			if (filteredPds == null) {
				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			}
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}
		// 如果當(dāng)前Bean中的BeanDefinition中設(shè)置了PropertyValues,那么最終將是PropertyValues中的值,覆蓋@Autowired
		if (pvs != null) {
			applyPropertyValues(beanName, mbd, bw, pvs);
		}![在這里插入圖片描述](https://img-blog.csdnimg.cn/fbf72b3c614c4efdb5b3ad5bfd6f5a6a.png)
	}

先是判斷BeanWrapper是否為空,為空則拋出異常,然后再進行實例化之后的步驟。

也就是執(zhí)行postProcessAfterInstantiation(Object bean, String beanName)方法

在這里插入圖片描述

這里是獲取該Bean的自動裝配模式,然后基于不同的裝配模式添加屬性值,Spring的自動裝配(autowire)有以下幾種模式:

  • no:這是默認(rèn)的設(shè)置,意味著沒有自動裝配,bean之間的關(guān)系需要通過 或 顯式配置。
  • byName:Spring容器通過bean的名稱自動裝配屬性。如果一個bean的屬性名稱與另一個bean的名稱相同,那么它們將被自動裝配。
  • byType:Spring容器通過類型自動裝配屬性。如果一個bean的屬性類型與另一個bean的類型相同,那么它們將被自動裝配。如果有多個相同類型的bean,則會拋出異常。
  • constructor:類似于 byType,但是適用于構(gòu)造函數(shù)。如果容器中存在不止一個與構(gòu)造函數(shù)參數(shù)相同類型的bean,則會拋出異常。
  • autodetect:Spring首先嘗試通過構(gòu)造函數(shù)自動裝配,如果不能通過構(gòu)造函數(shù)自動裝配,那么Spring會嘗試通過 byType 模式自動裝配。

自動裝配雖然可以減少配置的復(fù)雜性,但也可能引入歧義性。因此,對于大型項目,通常推薦使用顯式裝配。

在這里插入圖片描述

后面會根據(jù)緩存的注入點進行注入。injectionMetadataCache就是用來緩存注入點的。

在Spring框架中,injectionMetadataCache是AutowiredAnnotationBeanPostProcessor類(以及它的子類,如CommonAnnotationBeanPostProcessor)的一個成員變量。

在這里插入圖片描述

尋找注入點的過程主要發(fā)生在AutowiredAnnotationBeanPostProcessor類的findAutowiringMetadata方法中。這個方法首先會嘗試從injectionMetadataCache中獲取指定類的InjectionMetadata。如果沒有找到,就會創(chuàng)建一個新的InjectionMetadata,并將其添加到injectionMetadataCache中。

private InjectionMetadata findAutowiringMetadata(String beanName, Class<?> clazz, @Nullable PropertyValues pvs) {
		// Fall back to class name as cache key, for backwards compatibility with custom callers.
		String cacheKey = (StringUtils.hasLength(beanName) ? beanName : clazz.getName());
		// Quick check on the concurrent map first, with minimal locking.
		InjectionMetadata metadata = this.injectionMetadataCache.get(cacheKey);
		if (InjectionMetadata.needsRefresh(metadata, clazz)) {
			synchronized (this.injectionMetadataCache) {
				metadata = this.injectionMetadataCache.get(cacheKey);
				if (InjectionMetadata.needsRefresh(metadata, clazz)) {
					if (metadata != null) {
						metadata.clear(pvs);
					}
					// 解析注入點并緩存
					metadata = buildAutowiringMetadata(clazz);
					this.injectionMetadataCache.put(cacheKey, metadata);
				}
			}
		}
		return metadata;
	}

最主要的是通過類解析注入點的過程,buildAutowiringMetadata方法會通過類解析得到注入點的元數(shù)據(jù)。

private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
		// 如果一個Bean的類型是String...,那么則根本不需要進行依賴注入
		if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
			return InjectionMetadata.EMPTY;
		}

		List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
		Class<?> targetClass = clazz;

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

			// 遍歷targetClass中的所有Field
			ReflectionUtils.doWithLocalFields(targetClass, field -> {
				// field上是否存在@Autowired、@Value、@Inject中的其中一個
				MergedAnnotation<?> ann = findAutowiredAnnotation(field);
				if (ann != null) {
					// static filed不是注入點,不會進行自動注入
					if (Modifier.isStatic(field.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static fields: " + field);
						}
						return;
					}

					// 構(gòu)造注入點
					boolean required = determineRequiredStatus(ann);
					currElements.add(new AutowiredFieldElement(field, required));
				}
			});

			// 遍歷targetClass中的所有Method
			ReflectionUtils.doWithLocalMethods(targetClass, method -> {

				Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
				if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
					return;
				}
				// method上是否存在@Autowired、@Value、@Inject中的其中一個
				MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
				if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
					// static method不是注入點,不會進行自動注入
					if (Modifier.isStatic(method.getModifiers())) {
						if (logger.isInfoEnabled()) {
							logger.info("Autowired annotation is not supported on static methods: " + method);
						}
						return;
					}
					// set方法最好有入?yún)?
					if (method.getParameterCount() == 0) {
						if (logger.isInfoEnabled()) {
							logger.info("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 InjectionMetadata.forElements(elements, clazz);
	}

當(dāng)找到所有注入點就會返回。通過注入點注入主要是InstantiationAwareBeanPostProcessor接口中的PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName)方法實現(xiàn),在具體實現(xiàn)類AutowiredAnnotationBeanPostProcessor中找到了注入點的元數(shù)據(jù),就開始注入。

	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {
		// 找注入點(所有被@Autowired注解了的Field或Method)
		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;
	}

注入的元素會有兩種,一種是類的字段,還有一種是類的方法,不同類型的元素有不同的注入方法:

這是字段的注入

protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {

			Field field = (Field) this.member;
			Object value;
			if (this.cached) {
				// 對于原型Bean,第一次創(chuàng)建的時候,也找注入點,然后進行注入,此時cached為false,注入完了之后cached為true
				// 第二次創(chuàng)建的時候,先找注入點(此時會拿到緩存好的注入點),也就是AutowiredFieldElement對象,此時cache為true,也就進到此處了
				// 注入點內(nèi)并沒有緩存被注入的具體Bean對象,而是beanName,這樣就能保證注入到不同的原型Bean對象
				try {
					value = resolvedCachedArgument(beanName, this.cachedFieldValue);
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Unexpected removal of target bean for cached argument -> re-resolve
					value = resolveFieldValue(field, bean, beanName);
				}
			}
			else {
				// 根據(jù)filed從BeanFactory中查到的匹配的Bean對象
				value = resolveFieldValue(field, bean, beanName);
			}

			// 反射給filed賦值
			if (value != null) {
				ReflectionUtils.makeAccessible(field);
				field.set(bean, value);
			}
		}

這是方法的注入 方法的注入首先會去找到該方法參數(shù)的Bean對象,然后利用反射調(diào)用該方法

		@Override
		protected void inject(Object bean, @Nullable String beanName, @Nullable PropertyValues pvs) throws Throwable {
			// 如果pvs中已經(jīng)有當(dāng)前注入點的值了,則跳過注入
			if (checkPropertySkipping(pvs)) {
				return;
			}
			Method method = (Method) this.member;
			Object[] arguments;
			if (this.cached) {
				try {
					arguments = resolveCachedArguments(beanName);
				}
				catch (NoSuchBeanDefinitionException ex) {
					// Unexpected removal of target bean for cached argument -> re-resolve
					arguments = resolveMethodArguments(method, bean, beanName);
				}
			}
			else {
				arguments = resolveMethodArguments(method, bean, beanName);
			}
			if (arguments != null) {
				try {
					ReflectionUtils.makeAccessible(method);
					method.invoke(bean, arguments);
				}
				catch (InvocationTargetException ex) {
					throw ex.getTargetException();
				}
			}
		}

到此這篇關(guān)于Spring中的依賴注入DI源碼詳細(xì)解析的文章就介紹到這了,更多相關(guān)依賴注入DI源碼解析內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • mybatis抽取基類BaseMapper增刪改查的實現(xiàn)

    mybatis抽取基類BaseMapper增刪改查的實現(xiàn)

    目前項目當(dāng)中使用mapper.xml文件方式對數(shù)據(jù)庫進行操作,但是每個里邊都有增/刪/改/查,為了方便開發(fā),把這些公共的代碼提取出來,不用當(dāng)做基類,不用每個Mapper文件都寫了,本文就詳細(xì)的介紹一下實現(xiàn)方法
    2021-09-09
  • 配置javaw.exe雙擊運行jar包方式

    配置javaw.exe雙擊運行jar包方式

    這篇文章主要介紹了配置javaw.exe雙擊運行jar包方式,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-01-01
  • Java如何利用策略模式替代if/else語句

    Java如何利用策略模式替代if/else語句

    這篇文章主要介紹了Java如何利用策略模式替代if/else語句,幫助大家優(yōu)化自己的代碼,提高程序運行效率,感興趣的朋友可以了解下
    2020-09-09
  • Java之注解@Data和@ToString(callSuper=true)解讀

    Java之注解@Data和@ToString(callSuper=true)解讀

    在使用Lombok庫的@Data注解時,若子類未通過@ToString(callSuper=true)注明包含父類屬性,toString()方法只打印子類屬性,解決方法:1. 子類重寫toString方法;2. 子類使用@Data和@ToString(callSuper=true),父類也應(yīng)使用@Data
    2024-11-11
  • SpringBoot集成itext實現(xiàn)html轉(zhuǎn)PDF

    SpringBoot集成itext實現(xiàn)html轉(zhuǎn)PDF

    iText是著名的開放源碼的站點sourceforge一個項目,是用于生成PDF文檔的一個java類庫,本文主要介紹了如何利用itext實現(xiàn)html轉(zhuǎn)PDF,需要的可以參考下
    2024-03-03
  • 理解java設(shè)計模式之建造者模式

    理解java設(shè)計模式之建造者模式

    這篇文章主要幫助大家理解java設(shè)計模式之建造者模式,對建造者模式,即生成器模式進行實例講解,感興趣的朋友可以參考一下
    2016-02-02
  • Java 構(gòu)造方法的使用詳解

    Java 構(gòu)造方法的使用詳解

    構(gòu)造方法是類的一種特殊方法,用來初始化類的一個新的對象,在創(chuàng)建對象(new 運算符)之后自動調(diào)用。Java 中的每個類都有一個默認(rèn)的構(gòu)造方法,并且可以有一個以上的構(gòu)造方法
    2021-11-11
  • 詳解Spring中InitializingBean接口的功能

    詳解Spring中InitializingBean接口的功能

    這篇文章主要介紹了Spring中InitializingBean接口的功能,講述了spring中InitializingBean接口的功能簡介說明,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • 基于Spring實現(xiàn)搜索目錄下指定名稱文件

    基于Spring實現(xiàn)搜索目錄下指定名稱文件

    這篇文章主要為大家詳細(xì)介紹了如何基于Spring實現(xiàn)搜索目錄下指定名稱文件,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2025-08-08
  • Java中的vector類使用示例小結(jié)

    Java中的vector類使用示例小結(jié)

    Vector與ArrayList的實現(xiàn)基本相似,同樣是基于動態(tài)數(shù)組,同樣是需要擴容,下面舉了三個簡短的例子來幫助大家理解vertor:
    2016-05-05

最新評論

岚皋县| 永城市| 台中市| 四会市| 香格里拉县| 扎囊县| 古浪县| 惠水县| 通山县| 镇江市| 全州县| 白水县| 昌乐县| 伊春市| 连州市| 紫阳县| 定襄县| 加查县| 湘潭县| 德钦县| 华坪县| 望江县| 洪雅县| 铜川市| 乐都县| 敦煌市| 海丰县| 建宁县| 闵行区| 安平县| 新龙县| 砀山县| 萨迦县| 栾川县| 平泉县| 家居| 潼关县| 珠海市| 游戏| 精河县| 剑河县|