欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

springboot中@Value的工作原理說(shuō)明

 更新時(shí)間:2021年07月06日 11:50:59   作者:spring-hz  
這篇文章主要介紹了springboot中@Value的工作原理,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教

我們知道springboot中的Bean組件的成員變量(屬性)如果加上了@Value注解,可以從有效的配置屬性資源中找到配置項(xiàng)進(jìn)行綁定,那么這一切是怎么發(fā)生的呢?

下文將簡(jiǎn)要分析一下@Value的工作原理。

springboot版本: springboot-2.0.6.RELEASE

概述

springboot啟動(dòng)過(guò)程中,有兩個(gè)比較重要的過(guò)程,如下:

1 掃描,解析容器中的bean注冊(cè)到beanFactory上去,就像是信息登記一樣。

2 實(shí)例化、初始化這些掃描到的bean。

@Value的解析就是在第二個(gè)階段。BeanPostProcessor定義了bean初始化前后用戶可以對(duì)bean進(jìn)行操作的接口方法,它的一個(gè)重要實(shí)現(xiàn)類AutowiredAnnotationBeanPostProcessor正如javadoc所說(shuō)的那樣,為bean中的@Autowired和@Value注解的注入功能提供支持。

解析流程

調(diào)用鏈時(shí)序圖

@Value解析過(guò)程中的主要調(diào)用鏈,我用以下時(shí)序圖來(lái)表示:

在這里插入圖片描述

這里先簡(jiǎn)單介紹一下圖上的幾個(gè)類的作用。

AbstractAutowireCapableBeanFactory: 提供了bean創(chuàng)建,屬性填充,自動(dòng)裝配,初始胡。支持自動(dòng)裝配構(gòu)造函數(shù),屬性按名稱和類型裝配。實(shí)現(xiàn)了AutowireCapableBeanFactory接口定義的createBean方法。

AutowiredAnnotationBeanPostProcessor: 裝配bean中使用注解標(biāo)注的成員變量,setter方法, 任意的配置方法。比較典型的是@Autowired注解和@Value注解。

InjectionMetadata: 類的注入元數(shù)據(jù),可能是類的方法或?qū)傩缘?,在AutowiredAnnotationBeanPostProcessor類中被使用。

AutowiredFieldElement: 是AutowiredAnnotationBeanPostProcessor的一個(gè)私有內(nèi)部類,繼承InjectionMetadata.InjectedElement,描述注解的字段。

StringValueResolver: 一個(gè)定義了處置字符串值的接口,只有一個(gè)接口方法resolveStringValue,可以用來(lái)解決占位符字符串。本文中的主要實(shí)現(xiàn)類在PropertySourcesPlaceholderConfigurer#processProperties方法中通過(guò)lamda表達(dá)式定義的。供ConfigurableBeanFactory類使用。

PropertySourcesPropertyResolver: 屬性資源處理器,主要功能是獲取PropertySources屬性資源中的配置鍵值對(duì)。

PropertyPlaceholderHelper: 一個(gè)工具類,用來(lái)處理帶有占位符的字符串。形如${name}的字符串在該工具類的幫助下,可以被用戶提供的值所替代。替代途經(jīng)可能通過(guò)Properties實(shí)例或者PlaceholderResolver(內(nèi)部定義的接口)。

PropertyPlaceholderConfigurerResolver: 上一行所說(shuō)的PlaceholderResolver接口的一個(gè)實(shí)現(xiàn)類,是PropertyPlaceholderConfigurer類的一個(gè)私有內(nèi)部類。實(shí)現(xiàn)方法resolvePlaceholder中調(diào)用了外部類的resolvePlaceholder方法。

調(diào)用鏈說(shuō)明

這里主要介紹一下調(diào)用鏈中的比較重要的方法。

AbstractAutowireCapableBeanFactory#populateBean方法用于填充bean屬性,執(zhí)行完后可獲取屬性裝配后的bean。

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {       
...
if (hasInstAwareBpps) {
	// 遍歷所有InstantiationAwareBeanPostProcessor實(shí)例設(shè)置屬性字段值。
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		// AutowiredAnnotationBeanPostProcessor會(huì)進(jìn)入此分支
		if (bp instanceof InstantiationAwareBeanPostProcessor) {
			InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
			pvs = ibp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
		//上行代碼執(zhí)行后,bw.getWrappedInstance()就得到了@Value注解裝配屬性后的bean了
			if (pvs == null) {
				return;
			}
		}
	}
}
...
}

InjectionMetadata#inject逐個(gè)裝配bean的配置屬性。

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

PropertyPlaceholderHelper#parseStringValue解析屬性值

/**
 *  一個(gè)參數(shù)示例 value = "${company.ceo}"
 *
 */
protected String parseStringValue(
		String value, PlaceholderResolver placeholderResolver, Set<String> visitedPlaceholders) {
	StringBuilder result = new StringBuilder(value);
	// this.placeholderPrefix = "${"
	int startIndex = value.indexOf(this.placeholderPrefix);
	while (startIndex != -1) {
		// 占位符的結(jié)束位置,以value = "${company.ceo}"為例,endIndex=13
		int endIndex = findPlaceholderEndIndex(result, startIndex);
		if (endIndex != -1) {
			// 獲取{}里的真正屬性名稱,此例為"company.ceo"
			String placeholder = result.substring(startIndex + this.placeholderPrefix.length(), endIndex);
			String originalPlaceholder = placeholder;
			if (!visitedPlaceholders.add(originalPlaceholder)) {
				throw new IllegalArgumentException(
						"Circular placeholder reference '" + originalPlaceholder + "' in property definitions");
			}
			// Recursive invocation, parsing placeholders contained in the placeholder key.
			// 遞歸調(diào)用本方法,因?yàn)閷傩枣I中可能仍然有占位符
			placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
			// Now obtain the value for the fully resolved key...
			// 獲取屬性鍵placeholder對(duì)應(yīng)的屬性值
			String propVal = placeholderResolver.resolvePlaceholder(placeholder);
			// 此處邏輯是當(dāng)company.ceo=${bi:li}時(shí),company.ceo最終被li所替代的原因
			// 所以配置文件中,最好不要出現(xiàn)類似${}的東西,因?yàn)樗旧砭蜁?huì)被spring框架所解析
			if (propVal == null && this.valueSeparator != null) {
				int separatorIndex = placeholder.indexOf(this.valueSeparator);
				if (separatorIndex != -1) {
					String actualPlaceholder = placeholder.substring(0, separatorIndex);
					String defaultValue = placeholder.substring(separatorIndex + this.valueSeparator.length());
					propVal = placeholderResolver.resolvePlaceholder(actualPlaceholder);
					if (propVal == null) {
						propVal = defaultValue;
					}
				}
			}
			if (propVal != null) {
				// Recursive invocation, parsing placeholders contained in the
				// previously resolved placeholder value.
				propVal = parseStringValue(propVal, placeholderResolver, visitedPlaceholders);
				// 將${company.ceo}替換為li
				result.replace(startIndex, endIndex + this.placeholderSuffix.length(), propVal);
				if (logger.isTraceEnabled()) {
					logger.trace("Resolved placeholder '" + placeholder + "'");
				}
				startIndex = result.indexOf(this.placeholderPrefix, startIndex + propVal.length());
			}
			else if (this.ignoreUnresolvablePlaceholders) {
				// Proceed with unprocessed value.
				startIndex = result.indexOf(this.placeholderPrefix, endIndex + this.placeholderSuffix.length());
			}
			else {
				throw new IllegalArgumentException("Could not resolve placeholder '" +
						placeholder + "'" + " in value \"" + value + "\"");
			}
			visitedPlaceholders.remove(originalPlaceholder);
		}
		else {
			startIndex = -1;
		}
	}
	return result.toString();
}

總結(jié)

@Value注解標(biāo)注的bean屬性裝配是依靠AutowiredAnnotationBeanPostProcessor在bean的實(shí)例化、初始化階段完成的。以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • Spring 自動(dòng)裝配的二義性實(shí)例解析

    Spring 自動(dòng)裝配的二義性實(shí)例解析

    這篇文章主要介紹了Spring 自動(dòng)裝配的二義性實(shí)例解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2019-11-11
  • Java 8跳過(guò)本次循環(huán),繼續(xù)執(zhí)行以及跳出循環(huán),終止循環(huán)的代碼實(shí)例

    Java 8跳過(guò)本次循環(huán),繼續(xù)執(zhí)行以及跳出循環(huán),終止循環(huán)的代碼實(shí)例

    今天小編就為大家分享一篇關(guān)于Java 8跳過(guò)本次循環(huán),繼續(xù)執(zhí)行以及跳出循環(huán),終止循環(huán)的代碼實(shí)例,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2018-10-10
  • Java 后端開發(fā)中Tomcat服務(wù)器運(yùn)行不了的五種解決方案

    Java 后端開發(fā)中Tomcat服務(wù)器運(yùn)行不了的五種解決方案

    tomcat是在使用Java編程語(yǔ)言開發(fā)服務(wù)端技術(shù)使用最廣泛的服務(wù)器之一,但經(jīng)常在開發(fā)項(xiàng)目的時(shí)候會(huì)出現(xiàn)運(yùn)行不了的情況,這里總結(jié)出幾種能解決的辦法
    2021-10-10
  • JAVA實(shí)現(xiàn)異步調(diào)用實(shí)例代碼

    JAVA實(shí)現(xiàn)異步調(diào)用實(shí)例代碼

    在java平臺(tái),實(shí)現(xiàn)異步調(diào)用的角色主要三種角色:調(diào)用者、取貨憑證、真實(shí)數(shù)據(jù)。本篇文章給大家介紹java實(shí)現(xiàn)異步調(diào)用實(shí)例代碼,需要的朋友可以參考下
    2015-09-09
  • SpringBoot中實(shí)現(xiàn)@Scheduled動(dòng)態(tài)定時(shí)任務(wù)

    SpringBoot中實(shí)現(xiàn)@Scheduled動(dòng)態(tài)定時(shí)任務(wù)

    SpringBoot中的@Scheduled注解為定時(shí)任務(wù)提供了一種很簡(jiǎn)單的實(shí)現(xiàn),本文主要介紹了SpringBoot中實(shí)現(xiàn)@Scheduled動(dòng)態(tài)定時(shí)任務(wù),具有一定的參考價(jià)值,感興趣的可以了解一下
    2024-01-01
  • 淺談Java對(duì)象禁止使用基本類型

    淺談Java對(duì)象禁止使用基本類型

    本文主要介紹了淺談Java對(duì)象禁止使用基本類型,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • 使用@TableField(updateStrategy=FieldStrategy.IGNORED)遇到的坑記錄

    使用@TableField(updateStrategy=FieldStrategy.IGNORED)遇到的坑記錄

    這篇文章主要介紹了使用@TableField(updateStrategy=FieldStrategy.IGNORED)遇到的坑及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • Maven項(xiàng)目部署到服務(wù)器設(shè)置訪問(wèn)路徑以及配置虛擬目錄的方法

    Maven項(xiàng)目部署到服務(wù)器設(shè)置訪問(wèn)路徑以及配置虛擬目錄的方法

    今天小編就為大家分享一篇關(guān)于Maven項(xiàng)目部署到服務(wù)器設(shè)置訪問(wèn)路徑以及配置虛擬目錄的方法,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來(lái)看看吧
    2019-02-02
  • Java?超詳細(xì)講解設(shè)計(jì)模式之原型模式講解

    Java?超詳細(xì)講解設(shè)計(jì)模式之原型模式講解

    原型模式是用于創(chuàng)建重復(fù)的對(duì)象,同時(shí)又能保證性能。這種類型的設(shè)計(jì)模式屬于創(chuàng)建型模式,它提供了一種創(chuàng)建對(duì)象的最佳方式,今天通過(guò)本文給大家介紹下Java?原型設(shè)計(jì)模式,感興趣的朋友一起看看吧
    2022-03-03
  • SpringBoot各種注解詳解

    SpringBoot各種注解詳解

    SpringBoot的一個(gè)核心功能是IOC,就是將Bean初始化加載到容器中,Bean是如何加載到容器的,可以使用SpringBoot注解方式或者Spring XML配置方式。SpringBoot注解方式減少了配置文件內(nèi)容,更加便于管理,并且使用注解可以大大提高了開發(fā)效率
    2022-12-12

最新評(píng)論