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

【spring源碼系列-03】xml配置文件啟動spring時refresh的前置工作

這篇具有很好參考價值的文章主要介紹了【spring源碼系列-03】xml配置文件啟動spring時refresh的前置工作。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

Spring源碼系列整體欄目


內(nèi)容 鏈接地址
【一】spring源碼整體概述 https://blog.csdn.net/zhenghuishengq/article/details/130940885
【二】通過refresh方法剖析IOC的整體流程 https://blog.csdn.net/zhenghuishengq/article/details/131003428
【三】xml配置文件啟動spring時refresh的前置工作 https://blog.csdn.net/zhenghuishengq/article/details/131066637
【四】注解方式啟動spring時refresh的前置工作 https://blog.csdn.net/zhenghuishengq/article/details/131113249

一,xml配置文件啟動spring時refresh的前置工作

前兩篇大概的描述了一下springIoc的整體流程,接下來再對里面的細節(jié)進行分析。如下依舊是通過經(jīng)典的xml的方式獲取到上下文,并且在resources目錄下配置一個spring.xml文件,這里推薦使用debug的方式,從上往下看

ApplicationContext ioc=new ClassPathXmlApplicationContext("classpath:spring.xml");

【spring源碼系列-03】xml配置文件啟動spring時refresh的前置工作

進入這個獲取上下文的構造方法之后,可以發(fā)現(xiàn)有調(diào)用了這個this方法

public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
	this(new String[] {configLocation}, true, null);
}

接下來在進入這個this方法,就是一個熟悉的方法,該方法在前兩篇中有所提到。接下來重點就是對里面的前兩個方法進行深究,弄清refresh的前置工作到底做了什么

public ClassPathXmlApplicationContext(
	String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
	super(parent); // 初始化父類 ,獲得xml路徑資源解析器
	setConfigLocations(configLocations); // 通過環(huán)境變量解析 xml路徑
	if (refresh) {
		refresh(); // 這個方法時spring是最終要的一個方法,甚至體系整個ioc的聲明周期
	}
}

1,super(parent)

在該方法中,第一步就是初始化父類,后面很多需要使用的對象,就是在這一步被創(chuàng)建的,而里面的super繼續(xù)調(diào)用自己的super,直到創(chuàng)建一個資源模式處理器,該 AbstractApplicationContext 相對來說比較重要,并且那個最重要的refresh 方法就是在這個抽象類里面

public AbstractApplicationContext() {
    //獲取資源模式處理器
	this.resourcePatternResolver = getResourcePatternResolver();
}

接下來就是查看這個具體的獲取資源處理器的流程,里面的xml文件,或者其他的注解配置文件,都是能獲取的資源,獲取到資源之后就對資源進行一個解析操作

protected ResourcePatternResolver getResourcePatternResolver() {
	return new PathMatchingResourcePatternResolver(this);
}

接下來在查看這個 PathMatchingResourcePatternResolver 對象,可以發(fā)現(xiàn)里面就是獲取資源對象加載器。并且里面還存在一個對象PathMatcher,用做于路徑匹配

//用于模式匹配,默認使用的是 PathMatcher
private PathMatcher pathMatcher = new AntPathMatcher();
//獲取資源加載器
public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
	Assert.notNull(resourceLoader, "ResourceLoader must not be null");
	this.resourceLoader = resourceLoader;
}

在這個ResourceLoader 類中,主要就是兩個方法,一個是用于加載資源,一個是用于加載類加載器

//加載資源
Resource getResource(String location);
@Nullable
//加載類加載器
ClassLoader getClassLoader();

在這個 AbstractApplicationContext 構造方法中,完成this獲取一個資源解析器之后,接下來就是一個設置一個Parent的父類,當前springIOC中是沒有父子容器的概念的,因此到后續(xù)的springMVC再進行分析

public AbstractApplicationContext(@Nullable ApplicationContext parent) {
	this();
    //springIOC中暫時沒有父子容器概念,先跳過
	setParent(parent);
}

因此這一整個步驟,都是為了初始化成員變量。而最主要的,就是初始化一個資源的解析器。

2,setConfigLocations()

在獲取到這個資源解析器之后,接下來就是設置文件的路徑。如在正常開發(fā)的springboot項目中,通過設置環(huán)境的的屬性來表名是dev環(huán)境還是線上環(huán)境等。這個locations參數(shù)就是 new String[] {configLocation}

//參數(shù)可以是對象或者數(shù)組
public void setConfigLocations(@Nullable String... locations) {
	if (locations != null) {
		Assert.noNullElements(locations, "Config locations must not be null");
		this.configLocations = new String[locations.length];
		for (int i = 0; i < locations.length; i++) {
			this.configLocations[i] = resolvePath(locations[i]).trim();
		}
	}
	else {
		this.configLocations = null;
	}
}

2.1,獲取系統(tǒng)屬性和系統(tǒng)環(huán)境

在獲取到外部傳進來的文件路徑之后,接下來會通過這個 resolvePath方法解析這個路徑。而在解析這個路徑時,需要通過系統(tǒng)環(huán)境變量來解析,如果環(huán)境變量為空,則創(chuàng)建一個標準的環(huán)境變量

protected String resolvePath(String path) {
    //獲取環(huán)境
	return getEnvironment().resolveRequiredPlaceholders(path);
}

//如果獲取的環(huán)境為空,則創(chuàng)建一個標準環(huán)境
protected ConfigurableEnvironment createEnvironment() {
	return new StandardEnvironment();
}

而在這些環(huán)境中,存在一些spring環(huán)境變量的類型,分別是可忽視的,活躍的默認的等

public static final String IGNORE_GETENV_PROPERTY_NAME = "spring.getenv.ignore";
public static final String ACTIVE_PROFILES_PROPERTY_NAME = "spring.profiles.active";
public static final String DEFAULT_PROFILES_PROPERTY_NAME = "spring.profiles.default";
protected static final String RESERVED_DEFAULT_PROFILE_NAME = "default";

同時在這個標準環(huán)境中,主要分為系統(tǒng)環(huán)境和系統(tǒng)屬性等

【spring源碼系列-03】xml配置文件啟動spring時refresh的前置工作

//系統(tǒng)環(huán)境屬性資源名稱
static final String SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME = "systemEnvironment";
//系統(tǒng)配置變量資源名稱
static final String SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME = "systemProperties";

最后將全部的系統(tǒng)環(huán)境和系統(tǒng)屬性一起加入到 propertySources 這個PropertySources集合中,該集合是在父類中實例化的,因此會作為一個全局共享的資源,其子類都能獲取和訪問

protected void customizePropertySources(MutablePropertySources propertySources) {
	propertySources.addLast(
			new PropertiesPropertySource(SYSTEM_PROPERTIES_PROPERTY_SOURCE_NAME, getSystemProperties()));
	propertySources.addLast(
			new SystemEnvironmentPropertySource(SYSTEM_ENVIRONMENT_PROPERTY_SOURCE_NAME, getSystemEnvironment()));
}

加入到集合的value值主要是系統(tǒng)的變量和系統(tǒng)的環(huán)境。

//獲取系統(tǒng)的屬性值
getSystemProperties(){System.getProperties()};
//獲取系統(tǒng)的變量
getSystemEnvironment(){System.getenv()};

在創(chuàng)建這個 StandardEnvironment() 標準的環(huán)境的時候,可以在父類的無參構造方法中打一個斷點,可以發(fā)現(xiàn)此時會有兩個屬性值,就是上面的系統(tǒng)屬性值和系統(tǒng)環(huán)境值

【spring源碼系列-03】xml配置文件啟動spring時refresh的前置工作

而在下面的propertySourceList的第一個值systemProperties中,已經(jīng)加載了56個系統(tǒng)屬性,比如說一些 jdk的版本,虛擬機的版本,操作系統(tǒng)的名稱,當前用戶的名稱等等

【spring源碼系列-03】xml配置文件啟動spring時refresh的前置工作

在下面的propertySourceList的第二個值systemEnvironment中,也有49個值,比如說當前電腦的名稱,使用的maven路徑以及版本,java_home的路徑,用戶的用戶名等等

【spring源碼系列-03】xml配置文件啟動spring時refresh的前置工作

此時這些默認的環(huán)境對象和環(huán)境變量就全被獲取。當然這些環(huán)境變量的數(shù)量也可能因為源碼的版本不同個數(shù)也會不同。

2.2,解析系統(tǒng)環(huán)境和系統(tǒng)屬性

又回到上面的第二步,此時環(huán)境變量值依舊獲取,因此接下來就繼續(xù)執(zhí)行這個 resolveRequiredPlaceholders 方法

protected String resolvePath(String path) {
    //獲取環(huán)境
	return getEnvironment().resolveRequiredPlaceholders(path);
}

在resolveRequiredPlaceholders方法中,會獲取到剛剛全部獲取到的環(huán)境和屬性,然后對這些環(huán)境和屬性做一個解析操作。這里的話類似于一個責任鏈模式,系統(tǒng)環(huán)境要處理的會有對應的方法處理系統(tǒng)環(huán)境,系統(tǒng)屬性要處理的會有對應的方法處理系統(tǒng)屬性。下面這個是處理系統(tǒng)環(huán)境的方法

@Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
    //this.propertyResolver:全部的系統(tǒng)環(huán)境和系統(tǒng)屬性
	return this.propertyResolver.resolveRequiredPlaceholders(text);
}

處理完系統(tǒng)環(huán)境之后,會再次通過這個責任鏈模式,去處理對應的系統(tǒng)屬性,下面這個是處理系統(tǒng)屬性的方法

@Override
public String resolveRequiredPlaceholders(String text) throws IllegalArgumentException {
	if (this.strictHelper == null) {
		this.strictHelper = createPlaceholderHelper(false);
	}
    //解析工作
	return doResolvePlaceholders(text, this.strictHelper);
}

而在處理系統(tǒng)屬性時,會有一個 createPlaceholderHelper 方法,類似于一個builder的工廠類

private PropertyPlaceholderHelper createPlaceholderHelper(boolean ignoreUnresolvablePlaceholders) {
    //前綴,后綴
	return new PropertyPlaceholderHelper(this.placeholderPrefix, this.placeholderSuffix,
		this.valueSeparator, ignoreUnresolvablePlaceholders);
}

在獲取到這個strictHelper 對象之后,接下來開始真正的進行解析工作

private String doResolvePlaceholders(String text, PropertyPlaceholderHelper helper) {
	return helper.replacePlaceholders(text, this::getPropertyAsRawString);
}

再次進入這個replacePlaceholders 這個方法,可以發(fā)現(xiàn)里面會有一個重要的方法parseStringValue

public String replacePlaceholders(String value, PlaceholderResolver placeholderResolver) {
	Assert.notNull(value, "'value' must not be null");
	return parseStringValue(value, placeholderResolver, new HashSet < > ());
}

接下來查看這個 parseStringValue 方法,首先會判斷當前的value值中是否包含一個 $ 的大括號,并且會遞歸的判斷是否存在$ 的嵌套,判斷完成之后,會對里面的值進行解析。

【spring源碼系列-03】xml配置文件啟動spring時refresh的前置工作

在獲取完這個 符之后,接著就是遞歸的循環(huán)遍歷資源中的 k e y 值,將 < c o d e > 符之后,接著就是遞歸的循環(huán)遍歷資源中的key值,將<code> 符之后,接著就是遞歸的循環(huán)遍歷資源中的key值,將<code>{USERNAME} 對應的值進行一個替換操作。

String propVal = placeholderResolver.resolvePlaceholder(placeholder);

再次跟著debug斷點走,可以發(fā)現(xiàn)會進入 PropertySourcesPropertyResolver 類的 getProperty 方法里面

【spring源碼系列-03】xml配置文件啟動spring時refresh的前置工作

里面進行循環(huán)的取值,將${}里面的值和系統(tǒng)屬性或者系統(tǒng)變量的值進行匹配,如果匹配成功,則進行替換的操作

@Nullable
protected < T > T getProperty(String key, Class < T > targetValueType, boolean resolveNestedPlaceholders) {
	if (this.propertySources != null) {
		for (PropertySource << ? > propertySource : this.propertySources) {
            //取值
			Object value = propertySource.getProperty(key);
			if (value != null) {
                //取值成功,則進行替換操作
				if (resolveNestedPlaceholders && value instanceof String) {
					value = resolveNestedPlaceholders((String) value);
				}
				logKeyFound(key, propertySource, value);
                //如果需要的換則進行值轉換
				return convertValueIfNecessary(value, targetValueType);
			}
		}
	}
	return null;
}

接下來再進入轉換的convertValueIfNecessary 方法,如果不需要轉換則直接返回,需要轉換則轉換

@Nullable
protected < T > T convertValueIfNecessary(Object value, @Nullable Class < T > targetType) {
	if (targetType == null) {
		return (T) value;
	}
	ConversionService conversionServiceToUse = this.conversionService;
	if (conversionServiceToUse == null) {
		if (ClassUtils.isAssignableValue(targetType, value)) {
			return (T) value;
		}
		conversionServiceToUse = DefaultConversionService.getSharedInstance();
	}
    //轉換
	return conversionServiceToUse.convert(value, targetType);
}

如已知剛剛獲取到的系統(tǒng)環(huán)境變量中存在一個 USERNAME=‘PV’,那么假設xml的文件名為 spring-$ {USERNAME}.xml ,那么結果這個解析器進行解析之后,就會將這個${}里面的值進行一個替換操作,會將這個文件名變成 spring-PV.xml 文件。如果存在$的嵌套,那么就會遞歸的進行一個判斷和替換操作, 最終會將解析后的文件返回。

自此為止,屬性值就全部加載和解析完成。此時所有的配置文件路徑等,都添加在重要的類AbstractRefreshableConfigApplicationContextconfigLocations 的屬性里面。

private String[] configLocations;

除了剛剛舉例,還有像一些jdbc的連接參數(shù)等等,其原理都是一樣的,都是通過這種方式替換

"${jdbc.url}")
"${jdbc.driverClassName}"
"${jdbc.username}"
"${jdbc.password}"

3,總結

也就是通過這個xml的方式作為配置文件,在調(diào)用refresh方法之前,主要就是做了兩件事情:首先是初始化一個資源的解析器,隨后是獲取系統(tǒng)的屬性和系統(tǒng)的環(huán)境變量,同時對配置文件的路徑進行解析。至此為止,refresh需要準備的前戲工作結束。文章來源地址http://www.zghlxwxcb.cn/news/detail-473385.html

到了這里,關于【spring源碼系列-03】xml配置文件啟動spring時refresh的前置工作的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

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

領支付寶紅包贊助服務器費用

相關文章

  • Spring源碼(五)— 解析XML配置文件(二) 定制化標簽解析流程

    Spring源碼(五)— 解析XML配置文件(二) 定制化標簽解析流程

    上一篇以bean標簽為例,介紹了屬于defaultNamesapce標簽的解析流程,但是defaultNamespace中默認的標簽只有bean、beans、alias、import這四個,而我們平時在xml中配置的標簽有很多。那其余的標簽是如何解析? 在這篇文章會詳細介紹定制化標簽的解析流程。 注:除defaultNamesapce所屬的4個

    2024年02月15日
    瀏覽(33)
  • spring5源碼篇(13)——spring mvc無xml整合tomcat與父子容器的啟動

    spring5源碼篇(13)——spring mvc無xml整合tomcat與父子容器的啟動

    spring-framework 版本:v5.3.19 試想這么一個場景。只用 spring mvc(確切來說是spring-framework), 如何既不搭建web工程(無web.xml)又不用 spring boot 的去整合tomcat部署一個web服務? 1、引入 tomcat 和 spring mvc 2、實現(xiàn) WebApplicationInitializer接口,即本篇實現(xiàn)的spring mvc 提供的 AbstractAnnotati

    2024年02月15日
    瀏覽(24)
  • Spring系列二:基于XML配置bean

    Spring系列二:基于XML配置bean

    上文中, 我們學習到了 Spring系列一:spring的安裝與使用 接下來我們學習, 通過XML配置bean Bean管理包括兩方面: 創(chuàng)建bean對象, 給bean注入屬性 案例: 通過spring的ioc容器, 獲取一個bean對象, 獲取方式: 按類型. 演示通過bean的類型獲取對象 細節(jié) 按照類型獲取bean, 要求ioc容器中的同一個

    2024年02月14日
    瀏覽(19)
  • 【Spring進階系列丨第四篇】學習Spring中的Bean管理(基于xml配置)

    【Spring進階系列丨第四篇】學習Spring中的Bean管理(基于xml配置)

    在之前的學習中我們知道,容器是一個空間的概念,一般理解為可盛放物體的地方。在Spring容器通常理解為BeanFactory或者ApplicationContext。我們知道spring的IOC容器能夠幫我們創(chuàng)建對象,對象交給spring管理之后我們就不用手動去new對象。 那么Spring是如何管理Bean的呢? 簡而言之,

    2024年02月05日
    瀏覽(24)
  • Spring源碼之XML文件中Bean標簽的解析1

    Spring源碼之XML文件中Bean標簽的解析1

    xml文件里包含Bean的信息,為了避免多次IO,需要一次性讀取xml文件中所有bean信息,加入到Spring工廠。 讀取配置文件 ClassPathResource是Spring封裝的一個類型; Resource接口 :可以讀取相關資源文件的內(nèi)容 獲得輸入流;可讀取的類型,不僅包括本地的xml、 properties、txt 等文件,還包

    2024年02月13日
    瀏覽(27)
  • spring配置文件解讀——applicationContext.xml

    spring的配置文件-applicationContext.xml_聽著晴天看星晴的博客-CSDN博客

    2024年02月11日
    瀏覽(26)
  • Spring源碼解析——ApplicationContext容器refresh過程

    正文 在之前的博文中我們一直以BeanFactory接口以及它的默認實現(xiàn)類XmlBeanFactory為例進行分析,但是Spring中還提供了另一個接口ApplicationContext,用于擴展BeanFactory中現(xiàn)有的功能。 ApplicationContext和BeanFactory兩者都是用于加載Bean的,但是相比之下,ApplicationContext提供了更多的擴展功

    2024年02月08日
    瀏覽(27)
  • Spring高手之路16——解析XML配置映射為BeanDefinition的源碼

    Spring高手之路16——解析XML配置映射為BeanDefinition的源碼

    ?? Spring 框架中控制反轉( IOC )容器的 BeanDefinition 階段的具體步驟,主要涉及到 Bean 的定義、加載、解析,并在后面進行編程式注入和后置處理。這個階段是 Spring 框架中 Bean 生命周期的早期階段之一,對于理解整個 Spring 框架非常關鍵。 加載配置文件、配置類 ??在這

    2024年02月04日
    瀏覽(29)
  • 【細讀Spring Boot源碼】重中之重refresh()

    版本:spring-boot-2.7.3 | spring-context-5.3.22 在Spring Boot啟動過程中【細讀Spring Boot源碼】啟動步驟 主流程詳情7中 applicationContext.refresh(); 這個操作是加載或刷新容器,把所有的配置轉換成響應的對象并存入容器。 下面看下他的具體執(zhí)行流程 主流程使用了模板模式是一個模板方法

    2024年02月01日
    瀏覽(23)
  • logback-spring.xml日志配置文件詳解

    logback-spring.xml日志配置文件詳解

    打印日志是一個系統(tǒng)的基本功能,系統(tǒng)出現(xiàn)異常可以通過查找日志弄清楚是什么原因,從而更加快速地定位問題,修復系統(tǒng)。 文件位置 具體配置

    2024年02月15日
    瀏覽(33)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

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

二維碼1

領取紅包

二維碼2

領紅包