第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

Spring 工程執(zhí)行過程

1. 前言

Spring 框架是如何工作的?

本節(jié)目的在于幫助大家理解 Spring 框架底層干了什么事情。

在上一節(jié)中我們通過一個(gè)入門工程簡(jiǎn)單地體驗(yàn)了一把 Spring 的使用。

我們發(fā)現(xiàn),通過構(gòu)造一個(gè) ClassPathXmlApplicationContext 對(duì)象,加載項(xiàng)目的 applicationContext.xml 文件,確實(shí)可以實(shí)例化對(duì)象。

疑問導(dǎo)出

而腦海中不禁有一個(gè)想法… Spring 如何初始化對(duì)象的實(shí)例的?我們又如何從容器中獲取得到對(duì)象的實(shí)例的呢?

帶著疑問… 開啟本節(jié)的源碼和原理之旅。

2. 容器初始化

回顧代碼:

public static void main(String[] args) {
    ApplicationContext context =
            new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    UserService service = (UserService) context.getBean("userService");
    service.saveUser();
}

在上面的代碼中可以得知 Spring 的容器是 ApplicationContext,那么它到底是什么東西呢?先跟我一起追蹤一下它的角色。
官方文檔
圖片描述
慕課解釋

簡(jiǎn)單翻譯過來就是 ApplicationContext 是一個(gè) 接口,是 BeanFactory 這個(gè)接口的子接口,它擴(kuò)展了 BeanFactory 這個(gè)接口,提供了額外附加的功能。
BeanFactory 是管理 bean 對(duì)象的容器的根接口,大家了解下就好,我們是針對(duì)它的子接口 ClassPathXmlApplicationContext 做的實(shí)例化,目的是加載項(xiàng)目中的 Spring 的配置文件,使 Spring 來管理我們定義的 bean 對(duì)象。

疑問導(dǎo)出
那么我們的問題是…ClassPathXmlApplicationContext 對(duì)象實(shí)例化之后,干了哪些事情呢?

2.1 容器初始化執(zhí)行動(dòng)作

applicationContext 實(shí)例化執(zhí)行代碼邏輯 。
我們追蹤下源碼,發(fā)現(xiàn) ClassPathXmlApplicationContext 初始化的時(shí)候,它做了一系列的事情。源碼如下:
圖片描述

代碼解釋:

  1. 是初始化 ClassPathXmlApplicationContext 對(duì)象執(zhí)行的有參構(gòu)造;
  2. 加載項(xiàng)目下的 xml 配置文件;
  3. 調(diào)用 refresh 刷新容器的方法 bean 的實(shí)例化就在這個(gè)方法中。

繼續(xù)跟蹤:

2.2 容器初始化 bean 對(duì)象動(dòng)作

下面是從源碼中粘貼的部分代碼

圖片描述
步驟闡述:

對(duì)于我們而言 這些英文看起來很吃力… 放輕松大家,我們只關(guān)注對(duì)我們理解流程有用的代碼:

  1. 1 的位置:是準(zhǔn)備刷新,那么 Spring 只是設(shè)置刷新的標(biāo)記,加載了外部的 properties 屬性文件;
  2. 2 的位置:是準(zhǔn)備 bean 工廠對(duì)象;
  3. 3 的位置:這一步驟就加載了配置文件中的所有 bean 標(biāo)簽,但是并沒有對(duì)他們進(jìn)行實(shí)例化;
  4. 4 的位置:完成此上下文的 bean 工廠的初始化,初始化所有剩余的單例 bean。(Spring 中默認(rèn)加載的 bean 就是單例模式后面生命周期會(huì)講)
  5. 最后的位置:完成容器的刷新,也就是所有的 bean 初始化完成。
		//這里粘貼一部分初始化代碼的邏輯 幫助大家理解
		// Instantiate all remaining (non-lazy-init) singletons.
		beanFactory.preInstantiateSingletons();
		// Trigger initialization of all non-lazy singleton beans...
		//所有非懶加載的單例bean的觸發(fā)器初始化。。。
		for (String beanName : beanNames) {
		  ...//省略循環(huán)的代碼
		}

OK 上面就是加載配置文件后 Spring 框架做的所有事情,當(dāng)然實(shí)際底層涉及的東西 更多,但是我們沒有必要深究,畢竟我們是理解過程,不是追求實(shí)現(xiàn)。

疑問導(dǎo)出:

我們整理了 Spring 初始化 bean 對(duì)象的過程,那么如果容器中確實(shí)存在了 bean 的實(shí)例,我們是如何獲取得到的呢?

3. 容器中獲取對(duì)象的過程

還是先看下我們獲取容器對(duì)象的代碼:

public static void main(String[] args) {
    ApplicationContext context =
            new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
    UserService service = (UserService) context.getBean("userService");
    service.saveUser();
}

代碼分析

context.getBean 的方法是通過 bean 標(biāo)簽里的 id 來從容器中獲取,那么我們看下源碼 :
在父類 AbstractApplicationContext 中有對(duì) getBean 方法的實(shí)現(xiàn)。

	@Override
	public Object getBean(String name) throws BeansException {
		assertBeanFactoryActive();
		return getBeanFactory().getBean(name);
	}

追蹤父類方法
最終通過我們層層追蹤,我們?cè)?AbstractAutowireCapableBeanFactory 中發(fā)現(xiàn)這樣的一段代碼:

protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
			throws BeanCreationException {
		//...
		//省略大量方法內(nèi)部代碼
        //...
		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
            //給實(shí)例中的屬性賦值
			populateBean(beanName, mbd, instanceWrapper);
            //真實(shí)實(shí)例化對(duì)象
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		//...
        //繼續(xù)省略大量方法
        //...
		// Register bean as disposable.
		try {
            //將實(shí)例化后的對(duì)象放入容器中
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}
		//返回實(shí)例化后的對(duì)象實(shí)例
		return exposedObject;
	}

上面源碼中我們可以看到: 對(duì)象實(shí)例的獲取好像是在獲取的時(shí)候執(zhí)行的 doCreateBean,那么之前記載的 xml 文件不是實(shí)例過了嗎?稍微解釋下:加載文件時(shí)候的實(shí)例化操作,其實(shí)是實(shí)例化了一個(gè) Spring 框架提供的對(duì)象,作用是對(duì)于我們 bean 對(duì)象做描述,這里才是真實(shí)的實(shí)例化動(dòng)作。我們?cè)倏纯?registerDisposableBeanIfNecessary 這個(gè)方法做的是什么。

public void registerDisposableBean(String beanName, DisposableBean bean) {
		synchronized (this.disposableBeans) {
			this.disposableBeans.put(beanName, bean);
		}
	}

圖片描述
結(jié)論
一切真相大白。它其實(shí)就是一個(gè) map 集合 ,這個(gè) map 集合的 key 就是我們定義的 bean 的 id 或者 bean 的 name ,那么值就是對(duì)象的實(shí)例。

4. 小結(jié)

本章節(jié) 帶著大家梳理了一下 Spring 初始化 bean 和獲取 bean 的流程:

  1. Spring 框架通過 ResourceLoader 加載項(xiàng)目的 xml 配置文件;
  2. 讀取 xml 的配置信息 變成對(duì)象存儲(chǔ),但未實(shí)例化;
  3. 通過 bean 工廠處理器對(duì) bean 做實(shí)例化,存儲(chǔ)到一個(gè) map 集合中默認(rèn)是單例;
  4. 獲取對(duì)象 通過 xml 文件中 bean 的 id 從 map 集合中通過 get (key) 獲取。

羅馬不是一天建成的 ,書山有路勤為徑…