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

springboot中@Value的工作原理說明

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

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

下文將簡要分析一下@Value的工作原理。

springboot版本: springboot-2.0.6.RELEASE

概述

springboot啟動過程中,有兩個比較重要的過程,如下:

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

2 實例化、初始化這些掃描到的bean。

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

解析流程

調用鏈時序圖

@Value解析過程中的主要調用鏈,我用以下時序圖來表示:

在這里插入圖片描述

這里先簡單介紹一下圖上的幾個類的作用。

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

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

InjectionMetadata: 類的注入元數據,可能是類的方法或屬性等,在AutowiredAnnotationBeanPostProcessor類中被使用。

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

StringValueResolver: 一個定義了處置字符串值的接口,只有一個接口方法resolveStringValue,可以用來解決占位符字符串。本文中的主要實現類在PropertySourcesPlaceholderConfigurer#processProperties方法中通過lamda表達式定義的。供ConfigurableBeanFactory類使用。

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

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

PropertyPlaceholderConfigurerResolver: 上一行所說的PlaceholderResolver接口的一個實現類,是PropertyPlaceholderConfigurer類的一個私有內部類。實現方法resolvePlaceholder中調用了外部類的resolvePlaceholder方法。

調用鏈說明

這里主要介紹一下調用鏈中的比較重要的方法。

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

protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {       
...
if (hasInstAwareBpps) {
	// 遍歷所有InstantiationAwareBeanPostProcessor實例設置屬性字段值。
	for (BeanPostProcessor bp : getBeanPostProcessors()) {
		// AutowiredAnnotationBeanPostProcessor會進入此分支
		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逐個裝配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解析屬性值

/**
 *  一個參數示例 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) {
		// 占位符的結束位置,以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.
			// 遞歸調用本方法,因為屬性鍵中可能仍然有占位符
			placeholder = parseStringValue(placeholder, placeholderResolver, visitedPlaceholders);
			// Now obtain the value for the fully resolved key...
			// 獲取屬性鍵placeholder對應的屬性值
			String propVal = placeholderResolver.resolvePlaceholder(placeholder);
			// 此處邏輯是當company.ceo=${bi:li}時,company.ceo最終被li所替代的原因
			// 所以配置文件中,最好不要出現類似${}的東西,因為它本身就會被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();
}

總結

@Value注解標注的bean屬性裝配是依靠AutowiredAnnotationBeanPostProcessor在bean的實例化、初始化階段完成的。以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關文章

  • MybatisPlus的IPage失效的問題解決方案

    MybatisPlus的IPage失效的問題解決方案

    這篇文章主要介紹了MybatisPlus的IPage失效的問題解決方案,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2021-01-01
  • Spring Boot2.0實現靜態(tài)資源版本控制詳解

    Spring Boot2.0實現靜態(tài)資源版本控制詳解

    這篇文章主要給大家介紹了關于Spring Boot2.0實現靜態(tài)資源版本控制的相關資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-11-11
  • 詳解Spring MVC自動為對象注入枚舉類型

    詳解Spring MVC自動為對象注入枚舉類型

    本篇文章主要介紹了Spring MVC自動為對象注入枚舉類型,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • Struts2學習筆記(9)-Result配置全局結果集

    Struts2學習筆記(9)-Result配置全局結果集

    這篇文章主要介紹Struts2中使用Result配置全局結果集的方法,希望能給大家做一個參考。
    2016-06-06
  • SpringBoot整合dataworks的實現過程

    SpringBoot整合dataworks的實現過程

    這篇文章主要介紹了SpringBoot整合dataworks的實現過程,實現主要是編寫工具類,如果需要則可以配置成SpringBean,注入容器即可使用,需要的朋友可以參考下
    2022-08-08
  • Mybatis調用存儲過程的案例

    Mybatis調用存儲過程的案例

    這篇文章主要介紹了Mybatis如何調用存儲過程,本文通過示例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-07-07
  • vscode搭建java開發(fā)環(huán)境的實現步驟

    vscode搭建java開發(fā)環(huán)境的實現步驟

    本文主要介紹了vscode搭建java開發(fā)環(huán)境,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2023-03-03
  • JavaSwing坦克大戰(zhàn)游戲的設計和實現

    JavaSwing坦克大戰(zhàn)游戲的設計和實現

    JavaSwing坦克大戰(zhàn)游戲的設計要有圖形用戶界面,界面能夠反映游戲所有的細節(jié),在最終呈現的游戲中也要滿足所有需求,感興趣的小伙伴一起來看看吧
    2021-08-08
  • MySQL+SSM+Ajax上傳圖片問題

    MySQL+SSM+Ajax上傳圖片問題

    本文主要介紹了MySQL+SSM+Ajax上傳圖片問題。具有很好的參考價值。下面跟著小編一起來看下吧
    2017-03-03
  • 兩種Spring服務關閉時對象銷毀的實現方法

    兩種Spring服務關閉時對象銷毀的實現方法

    spring提供了兩種方式用于實現對象銷毀時去執(zhí)行的操作,本文主要為大家詳細介紹了這兩種方式的具體實現,文中的示例代碼講解詳細,希望對大家有所幫助
    2023-04-04

最新評論

景东| 四会市| 榆树市| 汝州市| 开封市| 屏边| 琼中| 乌拉特前旗| 商南县| 虎林市| 十堰市| 丰城市| 加查县| 张掖市| 晋城| 泊头市| 榆树市| 安塞县| 武功县| 广州市| 岳西县| 太仓市| 白沙| 张掖市| 阜新| 扎囊县| 馆陶县| 吐鲁番市| 白朗县| 嘉鱼县| 绍兴县| 怀柔区| 泸溪县| 黔西| 安康市| 江达县| 广汉市| 马山县| 尉氏县| 宣城市| 福海县|