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

【spring源碼系列-05】refresh中prepareRefresh方法的執(zhí)行流程

這篇具有很好參考價(jià)值的文章主要介紹了【spring源碼系列-05】refresh中prepareRefresh方法的執(zhí)行流程。希望對大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

Spring源碼系列整體欄目


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

一,深度剖析refresh的prepareRefresh方法

前兩篇談到了refresh方法的前置工作和準(zhǔn)備工作有哪些,注解的方式相對而言會(huì)比xml的方式需要做的前置工作更多。接下來就是進(jìn)入最主要的refresh部分,前面幾篇也粗略的對refresh里面的12個(gè)方法進(jìn)行了粗略的概括,接下來的文章中,將對每一個(gè)方法做一個(gè)詳細(xì)的概括。

再次查看這個(gè)refresh方法,首先會(huì)在這個(gè)方法上面加一個(gè)同步鎖 synchronized ,用來保證線程的安全性

@Override
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		//1:準(zhǔn)備刷新上下文環(huán)境
		prepareRefresh();
		//2:獲取告訴子類初始化Bean工廠,不同工廠有不同的實(shí)現(xiàn)
        //  并且將配置文件的屬性值加載到當(dāng)前工廠中
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
		//3:對bean工廠進(jìn)行填充屬性
		prepareBeanFactory(beanFactory);
		try {
			// 第四:留個(gè)子類去實(shí)現(xiàn)該接口,bean工廠的后置處理器
			postProcessBeanFactory(beanFactory);
			// 調(diào)用我們的bean工廠的后置處理器. 
       	 	//1. 會(huì)在此將class掃描成beanDefinition  2.bean工廠的后置處理器調(diào)用
			invokeBeanFactoryPostProcessors(beanFactory);
			// 注冊我們bean的后置處理器
			registerBeanPostProcessors(beanFactory);
			// 初始化國際化資源處理器.
			initMessageSource();
			// 創(chuàng)建事件多播器
			initApplicationEventMulticaster();
			// 這個(gè)方法同樣也是留個(gè)子類實(shí)現(xiàn)的springboot也是從這個(gè)方法進(jìn)行啟動(dòng)tomcat的.
			onRefresh();
			//把我們的事件監(jiān)聽器注冊到多播器上
			registerListeners();
			// 實(shí)例化我們剩余的單實(shí)例bean.
			finishBeanFactoryInitialization(beanFactory);
			// 最后容器刷新 發(fā)布刷新事件(Spring cloud也是從這里啟動(dòng)的)
			finishRefresh();
		}
    }
}

1,prepareRefresh()具體的執(zhí)行流程

接下來就是refresh中的第一個(gè)方法,也是本文的重點(diǎn):prepareRefresh(),顧名思義,就是刷新前的準(zhǔn)備工作,接下來進(jìn)入這個(gè)方法中,查看內(nèi)部詳細(xì)的執(zhí)行流程

【spring源碼系列-05】refresh中prepareRefresh方法的執(zhí)行流程

其主要代碼片段如下

protected void prepareRefresh() {
	// Switch to active.
	this.startupDate = System.currentTimeMillis();
	this.closed.set(false);
	this.active.set(true);
	/**
	 * 比如我們自己寫一個(gè)類重寫了initPropertySources方法,在該方法中設(shè)置了一個(gè)環(huán)境變量的值為A
	 * 啟動(dòng)的時(shí)候,我的環(huán)境變量中沒有該值就會(huì)啟動(dòng)拋出異常
	 */
	initPropertySources();

	/**
	 * 用來校驗(yàn)我們?nèi)萜鲉?dòng)必須依賴的環(huán)境變量的值
	 */
	getEnvironment().validateRequiredProperties();

	/**
	 * 創(chuàng)建一個(gè)早期事件監(jiān)聽器對象
	 */
	if (this.earlyApplicationListeners == null) {
		this.earlyApplicationListeners = new LinkedHashSet < > (this.applicationListeners);
	} else {
		this.applicationListeners.clear();
		this.applicationListeners.addAll(this.earlyApplicationListeners);
	}
	this.earlyApplicationEvents = new LinkedHashSet < > ();
}

1,首先第一個(gè)是記錄一下運(yùn)行這個(gè)方法時(shí)的起始時(shí)間,最后通過方法結(jié)束獲取的時(shí)間,來減去這個(gè)時(shí)間,就可以得到整個(gè)運(yùn)行refresh方法的差值

this.startupDate = System.currentTimeMillis();   //容器啟動(dòng)的時(shí)間

2,隨后就是設(shè)置兩個(gè)標(biāo)志位,一個(gè)是設(shè)置容器關(guān)閉的標(biāo)志位,一個(gè)是設(shè)置容器激活的標(biāo)志位

this.closed.set(false);   //容器關(guān)閉的標(biāo)志位
this.active.set(true);    //容器激活的標(biāo)志位

3,隨后就是一個(gè)重要的方法 initPropertySources() ,該方法是一個(gè)空方法,主要是留給子類自己去實(shí)現(xiàn),下面會(huì)專門舉一個(gè)小demo來理解這個(gè)方法的作用。

protected void initPropertySources() {
	// For subclasses: do nothing by default.
}

4,隨后一步就是先獲取系統(tǒng)環(huán)境對象,在進(jìn)入refresh方法之前就已經(jīng)獲取的 StandardEnvironment 實(shí)例對象,因此這里的環(huán)境對象不為空,直接將對象值返回。該對象內(nèi)部包含了全部的系統(tǒng)變量和系統(tǒng)屬性。

@Override
public ConfigurableEnvironment getEnvironment() {
	if (this.environment == null) {
		this.environment = createEnvironment();
	}
	return this.environment;
}

在拿到這個(gè)標(biāo)準(zhǔn)的環(huán)境對象之后,接下來就是通過這個(gè)validateRequiredProperties對里面的屬性進(jìn)行一個(gè)驗(yàn)證的操作

getEnvironment().validateRequiredProperties();

其對應(yīng)的驗(yàn)證操作如下,會(huì)循環(huán)遍歷這些屬性,判斷屬性在系統(tǒng)變量中是否存在,如果不存在則拋出異常

@Override
public void validateRequiredProperties() {
	MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
	for (String key: this.requiredProperties) {
        //判斷當(dāng)前屬性是否存在set集合中,即是否為系統(tǒng)屬性
		if (this.getProperty(key) == null) {
            //如果當(dāng)前屬性不是系統(tǒng)屬性,則添加一個(gè)異常
			ex.addMissingRequiredProperty(key);
		}
	}
    //如果異常數(shù)量不為空,則拋出異常
	if (!ex.getMissingRequiredProperties().isEmpty()) {
		throw ex;
	}
}

在這個(gè)拋出的異常中,就打印了這么一句話

The following properties were declared as required but could not be resolved: 

5,隨后一步就是創(chuàng)建一個(gè)事件監(jiān)聽對象,在spring啟動(dòng)的時(shí)候,這個(gè)早期的earlyApplicationListeners 監(jiān)聽器對象默認(rèn)為空,但是在springboot中,由于在spring.factories中存在大量的事件需要先加載,因此在springBoot中該對象不為空,相當(dāng)于是在spring的基礎(chǔ)上的一個(gè)增強(qiáng)。所以需要對這個(gè)earlyApplicationListeners對象判斷是都為空。

if (this.earlyApplicationListeners == null) {
    //spring使用,默認(rèn)為空
	this.earlyApplicationListeners = new LinkedHashSet <> (this.applicationListeners);
} else {
	// Reset local application listeners to pre-refresh state.
	//springboot使用,先清除原有的,再添加
    this.applicationListeners.clear();
	this.applicationListeners.addAll(this.earlyApplicationListeners);
}

如在spring.factories的文件中,默認(rèn)就會(huì)注入這么多的監(jiān)聽器。該功能主要是springboot的一個(gè)擴(kuò)展機(jī)制

【spring源碼系列-05】refresh中prepareRefresh方法的執(zhí)行流程

6,除了這個(gè)監(jiān)聽器在spring啟動(dòng)時(shí)為空之外,這個(gè)早期Event事件也為空。

this.earlyApplicationEvents = new LinkedHashSet<>();

2,initPropertySources(可擴(kuò)展)

由于initPropertySources 這個(gè)方法內(nèi)部是一個(gè)空方法,主要是留給子類去實(shí)現(xiàn),因此在這里,可以定義一個(gè)類繼承 ClassPathXmlApplicationContext 這個(gè)類,如下

/**
 * @author zhenghuisheng
 * @date : 2023/6/6
 */
public class MyClassPathXmlApplicationContext extends ClassPathXmlApplicationContext {
	
    //String... locations:xml配置文件的路徑
	public MyClassPathXmlApplicationContext(String... locations) {
		super(locations);
	}

	@Override
	protected void initPropertySources() { / /初始化屬性
		//設(shè)置屬性
		getEnvironment().setRequiredProperties("USERNAME");
		//獲取屬性
		String requiredProperty = getEnvironment().getRequiredProperty("USERNAME");
		System.out.println("當(dāng)前系統(tǒng)用戶名稱為:" + requiredProperty);
        //獲取app名稱
		String applicationName = getApplicationName();
		System.out.println("當(dāng)前應(yīng)用名稱為:" + applicationName);
		//獲取前置處理器
		List<BeanFactoryPostProcessor> list = getBeanFactoryPostProcessors();
		System.out.println("定義的bean工廠的后置處理器為的集合長度為:"+ list.size());
        ...
	}
}

在上一篇中有寫到,在refresh方法之前的前置工作中,就會(huì)獲取所有的系統(tǒng)環(huán)境和系統(tǒng)變量,如下圖就是系統(tǒng)環(huán)境變量

【spring源碼系列-05】refresh中prepareRefresh方法的執(zhí)行流程

因此這里可以直接拿到這些環(huán)境變量等。隨后寫一個(gè)主啟動(dòng)類進(jìn)行測試

 public static void main(String[] args) {
    //擴(kuò)展,用于鑒定屬性
	ApplicationContext m = new MyClassPathXmlApplicationContext("classpath.a.xml");    
}

由于環(huán)境對象可以獲取到,因此在這個(gè)環(huán)境變量里面設(shè)置一個(gè)屬性

getEnvironment().setRequiredProperties("USERNAME");

上面設(shè)置的屬性 USERNAME值,在設(shè)置之后會(huì)進(jìn)行一個(gè)驗(yàn)證的操作,主要是驗(yàn)證該值在系統(tǒng)中是否存在,如果不存在則直接拋出異常。

void validateRequiredProperties() throws MissingRequiredPropertiesException;

開發(fā)中如果程序是需要包含某個(gè)值, 如需要某個(gè)屬性或者某個(gè)前綴之類的,就可以在這一步進(jìn)行判斷,就不用進(jìn)應(yīng)用層里面去判斷了。如在抽象類 AbstractEnvironment 中,有著這兩個(gè)的具體實(shí)現(xiàn),可以先設(shè)置值,隨后會(huì)對設(shè)置的值進(jìn)行驗(yàn)證。

//設(shè)置相關(guān)的屬性值
@Override
public void setRequiredProperties(String...requiredProperties) {
	this.propertyResolver.setRequiredProperties(requiredProperties);
}
//驗(yàn)證屬性值,屬性在在系統(tǒng)屬性中不存在,則立馬拋出異常
@Override
public void validateRequiredProperties() throws MissingRequiredPropertiesException {
	this.propertyResolver.validateRequiredProperties();
}

驗(yàn)證的流程具體如下:判斷當(dāng)前系統(tǒng)屬性有沒有這個(gè)值,如果系統(tǒng)有這個(gè)值,則不管;沒有這個(gè)值,則拋出異常報(bào)錯(cuò)

@Override
public void validateRequiredProperties() {
	MissingRequiredPropertiesException ex = new MissingRequiredPropertiesException();
	for (String key: this.requiredProperties) {
        //判斷當(dāng)前系統(tǒng)屬性有沒有這個(gè)值
		if (this.getProperty(key) == null) {
			ex.addMissingRequiredProperty(key);
		}
	}
    //如果系統(tǒng)有這個(gè)值,則不管;沒有這個(gè)值,則拋出異常報(bào)錯(cuò)
	if (!ex.getMissingRequiredProperties().isEmpty()) {
		throw ex;
	}
}

主要作用就是提前做一個(gè)參數(shù)的校驗(yàn),實(shí)際開發(fā)中用的也比較少。

3,總結(jié)

在這個(gè)prepareRefresh方法中,總結(jié)來說就是做了五件事情:設(shè)置容器啟動(dòng)時(shí)間、設(shè)置活躍狀態(tài)為true、設(shè)置關(guān)閉狀態(tài)為false、獲取環(huán)境對象,并將當(dāng)前系統(tǒng)的屬性值設(shè)置到Environment對象中、實(shí)例化監(jiān)聽器對象和事件對象,并設(shè)置為空文章來源地址http://www.zghlxwxcb.cn/news/detail-481251.html

到了這里,關(guān)于【spring源碼系列-05】refresh中prepareRefresh方法的執(zhí)行流程的文章就介紹完了。如果您還想了解更多內(nèi)容,請?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)載,請注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

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

相關(guān)文章

  • Spring 6 IOC容器加載過程與核心方法refresh源碼淺析

    Spring 6 IOC容器加載過程與核心方法refresh源碼淺析

    前言:本篇只對主線核心邏輯進(jìn)行梳理分析,本篇以AnnotationConfigApplicationContext容器為例進(jìn)行切入分析【Spring版本為: v6.0.2】 我們啟動(dòng)容器的時(shí)候,雖然只是new了一個(gè)AnnotationConfigApplicationContext對象,但是在這個(gè)過程中spring處理了很多的事情。 創(chuàng)建AnnotationConfigApplicationContext對象

    2023年04月08日
    瀏覽(23)
  • 【深入淺出Spring原理及實(shí)戰(zhàn)】「源碼調(diào)試分析」深入源碼探索Spring底層框架的的refresh方法所出現(xiàn)的問題和異常

    閱讀Spring官方文檔,了解Spring框架的基本概念和使用方法。 下載Spring源碼,可以從官網(wǎng)或者GitHub上獲取。 閱讀Spring源碼的入口類,了解Spring框架的啟動(dòng)過程和核心組件的加載順序。 閱讀Spring源碼中的注釋和文檔,了解每個(gè)類和方法的作用和用法。 調(diào)試Spring源碼,可以通過

    2023年04月23日
    瀏覽(33)
  • Spring源碼解析——ApplicationContext容器refresh過程

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

    2024年02月08日
    瀏覽(27)
  • 【細(xì)讀Spring Boot源碼】重中之重refresh()

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

    2024年02月01日
    瀏覽(24)
  • 【源碼系列#05】Vue3響應(yīng)式原理(Ref)

    ref: 接受一個(gè)參數(shù)值并返回一個(gè)響應(yīng)式且可改變的 ref 對象。ref 對象擁有一個(gè)指向內(nèi)部值的單一屬性 .value 可以將 ref 看成 reactive 的一個(gè)變形版本,這是由于 reactive 內(nèi)部采用 Proxy 來實(shí)現(xiàn),而 Proxy 只接受對象作為入?yún)?,這才有了 ref 來解決值類型的數(shù)據(jù)響應(yīng), 如果傳入 ref 的

    2024年02月03日
    瀏覽(62)
  • 【jvm系列-05】精通運(yùn)行時(shí)數(shù)據(jù)區(qū)共享區(qū)域---方法區(qū)

    【jvm系列-05】精通運(yùn)行時(shí)數(shù)據(jù)區(qū)共享區(qū)域---方法區(qū)

    JVM系列整體欄目 內(nèi)容 鏈接地址 【一】初識(shí)虛擬機(jī)與java虛擬機(jī) https://blog.csdn.net/zhenghuishengq/article/details/129544460 【二】jvm的類加載子系統(tǒng)以及jclasslib的基本使用 https://blog.csdn.net/zhenghuishengq/article/details/129610963 【三】運(yùn)行時(shí)私有區(qū)域之虛擬機(jī)棧、程序計(jì)數(shù)器、本地方法棧 https

    2023年04月09日
    瀏覽(22)
  • 【spring源碼系列-01】spring底層源碼整體概述

    【spring源碼系列-01】spring底層源碼整體概述

    Spring源碼系列整體欄目 內(nèi)容 鏈接地址 【一】spring源碼整體概述 https://blog.csdn.net/zhenghuishengq/article/details/130940885 【二】通過refresh方法剖析IOC的整體流程 https://blog.csdn.net/zhenghuishengq/article/details/131003428 【三】xml配置文件啟動(dòng)spring時(shí)refresh的前置工作 https://blog.csdn.net/zhenghuishen

    2024年02月07日
    瀏覽(33)
  • Spring源碼系列:初探底層,手寫Spring

    Spring源碼系列:初探底層,手寫Spring

    在學(xué)習(xí)Spring框架源碼時(shí),記住一句話:源碼并不難,只需要給你各種業(yè)務(wù)場景或者項(xiàng)目經(jīng)理,你也能實(shí)現(xiàn)自己的Spring。雖然你的實(shí)現(xiàn)可能無法與開源團(tuán)隊(duì)相媲美,但是你肯定可以實(shí)現(xiàn)一個(gè)0.0.1版本。因此,初次閱讀源碼時(shí),不要陷入太深的細(xì)節(jié)中。先了解大體邏輯,再仔細(xì)研

    2023年04月12日
    瀏覽(20)
  • Spring源碼系列:核心概念解析

    Spring源碼系列:核心概念解析

    本文旨在為讀者解析Spring源碼中的關(guān)鍵類,以便讀者在深入閱讀源碼時(shí),能夠了解關(guān)鍵類的作用和用途。在閱讀Spring源碼時(shí),經(jīng)常會(huì)遇到一些不熟悉的概念,了解關(guān)鍵類的作用可以幫助讀者更好地理解這些概念。 BeanDefinition是Spring框架中的一個(gè)重要概念,它定義了一個(gè)Bean的基

    2023年04月20日
    瀏覽(26)
  • NDK編譯系列:手機(jī)終端運(yùn)行可執(zhí)行文件的方法

    該方式為PC上的NDK工具生成的可執(zhí)行文件和庫,利用adb導(dǎo)入到手機(jī)(未采用Andriod Studio生成帶界面的apk文件),直接通過windows的命令窗在安卓原生linux環(huán)境上運(yùn)行仿真。 利用前文博客總結(jié)梳理的方法,假設(shè)已經(jīng)生成了可在手機(jī)終端運(yùn)行的二進(jìn)制文件和相關(guān)動(dòng)態(tài)庫,我們該如何

    2024年02月16日
    瀏覽(23)

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

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

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

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

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包