16-Spring源碼解析之Bean的生命週期(1)——doGetBean

Spring版本:<version>5.2.1.RELEASE</version>

上一篇:15-Spring源碼解析之refresh(8)——【finishBeanFactoryInitialization】

本篇我們來解決上一篇中遺留的問題,即finishBeanFactoryInitialization中是如何通過getBean來創建Bean實例的。

爲了更好更清晰的理解Bean的生命週期。我首先給出一個很簡單的例子。這個例子包含:

  • 實體類(User)
    • 實現了InitializingBean 接口,實現這個接口的目的是更好的看afterPropertiesSet方法的執行時機
    • 這個類不包含@Autowired@Value@Resource等註解,因爲這些註解需要在Bean創建的時候進行解析,爲了更好的理解Bean生命週期的整體邏輯,這裏先不額外增加以上註解,後續文章會講解這些註解在Bean創建中的哪一步起作用。
  • 自定義BeanPostProcessorMyBeanPostProcessor
    • 實現了BeanPostProcessor接口,重寫postProcessBeforeInitialization方法和postProcessAfterInitialization方法。
    • 例子中包含這個接口的目的是爲了看 postProcessBeforeInitializationpostProcessAfterInitialization的執行時機
  • 配置類(MainConfig)
    • 這個類只有兩個註解:
      • @Configuration:標註當前類是配置類的註解,用於標註Spring首先解析的類
      • @ComponentScan:包掃描註解,用於掃描 實現類User和自定義類MyBeanPostProcessor

下面給出這個例子的源代碼

一、例子

包結構

在這裏插入圖片描述

1. 實體類User

package com.spring.csdn;

import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;

@Component
public class User implements InitializingBean {

    private String name;

    public User() {
        System.out.println("User類的 【無參構造器】");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("User類的 【afterPropertiesSet】 方法");
    }
}

2. 自定義BeanPostProcessorMyBeanPostProcessor

package com.spring.postprocessor;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessBeforeInitialization -> 當前類爲:" + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("postProcessAfterInitialization -> " + beanName);
        return bean;
    }
}

3. 配置類MainConfig

package com.spring.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.spring")
public class MainConfig {

}

4. 測試類Test

package com.spring;

import com.spring.config.MainConfig;
import com.spring.csdn.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        User user = applicationContext.getBean(User.class);
    }
}

5. 輸出結果

在這裏插入圖片描述

我們知道BeanPostProcessor會攔截每個Bean的創建,然後在每個Bean的初始化方法執行前執行postProcessBeforeInitialization,在初始化方法執行後執行postProcessAfterInitialization。所以可以看到輸出結果中,回對Spring中的每一個類都執行了postProcessBeforeInitializationpostProcessAfterInitialization方法。 而有關構造器和afterPropertiesSet的執行時機,我們下面來慢慢分析。

二、getBean獲取Bean實例

2.1 當前beanFactory中的值

上一篇文章,我們講到了finishBeanFactoryInitialization方法在最後會調用getBean方法獲取Bean實例。那麼接下我們就具體看一下它是如何獲取到Bean實例的。

在看這個方法之前,我們有必要看一下當前BeanDefinition的情況,以及beanFactory已經創建Bean的情況。

beanDefintion的情況:
在這裏插入圖片描述

beanFactoryregisteredSingletons屬性保存已經創建的Bean的情況。
在這裏插入圖片描述
從上面圖片可以看出當前容器中有12個Bean已經被創建了,其中只有registeredSingletons[9]是我們自己的Bean,其他的都是Spring內部自己創建的Bean,我們暫時不考慮Spring內部自己創建的Bean的作用(因爲涉及的內容太多了,有一些已經在前面的文章中講過了)。

接下來是真正到了看一下finishBeanFactoryInitialization是如何獲取到Bean實例的時候了。

2.2 getBean方法

我們以獲取User類爲例子進行講解。接着上篇文章,上篇文章在最後finishBeanFactoryInitialization方法調用preInstantiateSingletons方法,preInstantiateSingletons方法在每一個for循環裏面調用getBean方法。現在我們就進入getBean方法。

	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}

它調用的是AbstractBeanFactory類的getBean方法,我們可以看一下AbstractBeanFactory類實際上有4個getBean方法。

在這裏插入圖片描述
注意,在初始化容器的時候,調用的是getBean(String)方法。但是這裏還需要注意的另外一個事情是:雖然AbstractBeanFactory類有4個getBean方法,但是每個方法都調用了doGetBean方法,且AbstractBeanFactorydoGetBean方法只有一個。

	@Override
	public Object getBean(String name) throws BeansException {
		return doGetBean(name, null, null, false);
	}
	@Override
	public <T> T getBean(String name, Class<T> requiredType) throws BeansException {
		return doGetBean(name, requiredType, null, false);
	}
	@Override
	public Object getBean(String name, Object... args) throws BeansException {
		return doGetBean(name, null, args, false);
	}
	public <T> T getBean(String name, @Nullable Class<T> requiredType, @Nullable Object... args)
			throws BeansException {

		return doGetBean(name, requiredType, args, false);
	}

2.3 doGetBean

高能預警:這個doGetBean做了好多事情,而且代碼有點長。

	protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType,
			@Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {

// ------------------------------------------【功能一】--2.3.1詳細介紹----------------------------------------
// ------------------------------------------轉換對應 beanName----------------------------------------

		final String beanName = transformedBeanName(name);
		Object bean;

// ------------------------------------------【功能二】--2.3.2詳細介紹----------------------------------------
// ------------------------------------------嘗試從緩存中加載單例----------------------------------------

		// Eagerly check singleton cache for manually registered singletons.
		Object sharedInstance = getSingleton(beanName);
		
// ------------------------------------------根據【功能二】返回的結果進行------------------------------------------
// ------------------------------------------【功能三】------------------------------------------
		if (sharedInstance != null && args == null) {
			if (logger.isTraceEnabled()) {
				if (isSingletonCurrentlyInCreation(beanName)) {
					logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
							"' that is not fully initialized yet - a consequence of a circular reference");
				}
				else {
					logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
				}
			}
			// -------------------------------------------------------------------------
			bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
		}
// ------------------------------------------根據【功能二】返回的結果進行------------------------------------------
		else {
			// Fail if we're already creating this bean instance:
			// We're assumably within a circular reference.
// ------------------------------------------【功能三】------------------------------------------
			// 只有singleton情況下才會嘗試解決循環依賴
			if (isPrototypeCurrentlyInCreation(beanName)) {
				throw new BeanCurrentlyInCreationException(beanName);
			}
// ------------------------------------------【功能四】------------------------------------------
			// Check if bean definition exists in this factory.
			BeanFactory parentBeanFactory = getParentBeanFactory();
			if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
				// Not found -> check parent.
				String nameToLookup = originalBeanName(name);
				if (parentBeanFactory instanceof AbstractBeanFactory) {
					return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
							nameToLookup, requiredType, args, typeCheckOnly);
				}
				else if (args != null) {
					// Delegation to parent with explicit args.
					return (T) parentBeanFactory.getBean(nameToLookup, args);
				}
				else if (requiredType != null) {
					// No args -> delegate to standard getBean method.
					return parentBeanFactory.getBean(nameToLookup, requiredType);
				}
				else {
					return (T) parentBeanFactory.getBean(nameToLookup);
				}
			}
// ------------------------------------------【功能五】---2.3.3詳細介紹---------------------------------------
			if (!typeCheckOnly) {
				// 將創建的Bean加入到beanFactory的alreadyCreated屬性中
				markBeanAsCreated(beanName);
			}
// ------------------------------------------【功能六】------------------------------------------
			try {
				// BeanDfinitiaon定義公共的抽象累是AbstractBeanDefinition。
				// 普通的Bean在Spring註冊BeanDefinition的時候,實例化出來的是GenericBeanDefinition
				// Spring內置的Bean在註冊BeanDefinition的時候,實例化出來的是RootBeanDefinition,
				// 這時候,就要用getMergedLocalBeanDefinition將所有的BeanDefinition都轉換爲RootBeanDefinition
				final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
				checkMergedBeanDefinition(mbd, beanName, args);
// ------------------------------------------【功能七】--尋找依賴----------------------------------------
				// Guarantee initialization of beans that the current bean depends on.
				// 若當前Bean有依賴,則先創建依賴Bean
				String[] dependsOn = mbd.getDependsOn();
				if (dependsOn != null) {
					for (String dep : dependsOn) {
						if (isDependent(beanName, dep)) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
						}
						registerDependentBean(dep, beanName);
						try {
							getBean(dep);
						}
						catch (NoSuchBeanDefinitionException ex) {
							throw new BeanCreationException(mbd.getResourceDescription(), beanName,
									"'" + beanName + "' depends on missing bean '" + dep + "'", ex);
						}
					}
				}
// ------------------------------------------【功能八】核心方法:下一篇文章重點介紹---------------------------------------
				// 針對不同的scope進行bean的創建

				// ---------------------------【Singleton】類型---------------------------
				if (mbd.isSingleton()) {
					// 核心方法:下一篇文章重點介紹!!!
					sharedInstance = getSingleton(beanName, () -> {
						try {
							return createBean(beanName, mbd, args);
						}
						catch (BeansException ex) {
							// Explicitly remove instance from singleton cache: It might have been put there
							// eagerly by the creation process, to allow for circular reference resolution.
							// Also remove any beans that received a temporary reference to the bean.
							destroySingleton(beanName);
							throw ex;
						}
					});
					bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
				}


				// ---------------------------【Prototype】類型---------------------------
				else if (mbd.isPrototype()) {
					// It's a prototype -> create a new instance.
					Object prototypeInstance = null;
					try {
						beforePrototypeCreation(beanName);
						prototypeInstance = createBean(beanName, mbd, args);
					}
					finally {
						afterPrototypeCreation(beanName);
					}
					bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
				}

				// ---------------------------【其他Scope】類型---------------------------
				else {
					String scopeName = mbd.getScope();
					final Scope scope = this.scopes.get(scopeName);
					if (scope == null) {
						throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
					}
					try {
						Object scopedInstance = scope.get(beanName, () -> {
							beforePrototypeCreation(beanName);
							try {
								return createBean(beanName, mbd, args);
							}
							finally {
								afterPrototypeCreation(beanName);
							}
						});
						bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
					}
					catch (IllegalStateException ex) {
						throw new BeanCreationException(beanName,
								"Scope '" + scopeName + "' is not active for the current thread; consider " +
								"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
								ex);
					}
				}
			}
			catch (BeansException ex) {
				cleanupAfterBeanCreationFailure(beanName);
				throw ex;
			}
		}
// ------------------------------------------【功能九】------------------------------------------
		// Check if required type matches the type of the actual bean instance.
		if (requiredType != null && !requiredType.isInstance(bean)) {
			try {
				T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
				if (convertedBean == null) {
					throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
				}
				return convertedBean;
			}
			catch (TypeMismatchException ex) {
				if (logger.isTraceEnabled()) {
					logger.trace("Failed to convert bean '" + name + "' to required type '" +
							ClassUtils.getQualifiedName(requiredType) + "'", ex);
				}
				throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
			}
		}
		return (T) bean;
	}

在本文的最後會總結doGetBean方法的功能,我們先一步步拆解這裏面的每個功能所作的事情。

2.3.1 【功能一】 transformedBeanName

根據這個方法的名字可以知道,該方法的作用是:轉換對於的beanName,那這裏爲什麼要轉換呢?
實際上,在創建Spring容器的過程中是不需要轉換beanName的,因此在創建Spring容器的時候,該方法還是將我們原來的beanName返回。

但是當我們在獲取Spring容器之後,自己在程序中調用getBean方法的時候,就可能會用到這個方法。比如我們在程序中寫:

public class Test {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class);
        PeopleFactory peopleFactory = (PeopleFactory)applicationContext.getBean("&people");
    }
}

在寫applicationContext.getBean();的時候,我們會給getBean方法傳入String類型的參數。當獲取的bean是一個實現了FactoryBean接口的類的時候,transformedBeanName方法就起作用了。

下面看一下transformedBeanName方法的實現:

	protected String transformedBeanName(String name) {
		return canonicalName(BeanFactoryUtils.transformedBeanName(name));
	}

從上面方法可以看出,transformedBeanName首先調用了BeanFactoryUtils.transformedBeanName

	// BeanFactoryUtils類的transformedBeanName方法
	// String FACTORY_BEAN_PREFIX = "&";
	public static String transformedBeanName(String name) {
		Assert.notNull(name, "'name' must not be null");
		if (!name.startsWith(BeanFactory.FACTORY_BEAN_PREFIX)) {
			return name;
		}
		return transformedBeanNameCache.computeIfAbsent(name, beanName -> {
			do {
				beanName = beanName.substring(BeanFactory.FACTORY_BEAN_PREFIX.length());
			}
			while (beanName.startsWith(BeanFactory.FACTORY_BEAN_PREFIX));
			return beanName;
		});
	}

可以看出,先去除FactoryBean的修飾符&,即如果name = &people,那麼會首先除去&而使name = people
返回後transformedBeanName方法又調用canonicalName方法

	public String canonicalName(String name) {
		String canonicalName = name;
		// Handle aliasing...
		String resolvedName;
		do {
			resolvedName = this.aliasMap.get(canonicalName);
			if (resolvedName != null) {
				canonicalName = resolvedName;
			}
		}
		while (resolvedName != null);
		return canonicalName;
	}

2.3.2 【功能二】getSingleton從緩存中加載單例

單例在Spring的同一個容器中只會被創建一次,創建完成後,會把創建好的Bean加入到緩存中。

因此Spring每次在getSingleton獲取Bean的時候會先嚐試從緩存中加載,如果加載不成功再次從singletonFactories中加載。因爲在創建單例Bean的時候會存在依賴注入的情況,而在創建依賴的時候爲了避免循環依賴,在Spring中創建Bean的時候,執行createBean -> doCreateBean -> createBeanInstance之後,就會將剛實例化好還沒有進行屬性注入(populate)的Bean加入到緩存中。一旦下一個Bean創建的時候需要依賴上一個Bean,則直接使用ObjectFactory

我們先來看看getSingleton方法所在的類:

在這裏插入圖片描述
這個類有3個getSingleton方法。而我們從緩存中加載單例是調用的getSingleton(beanName)方法。

下面我們來具體看一下Spring是怎麼從緩存中加載單例的。

	public Object getSingleton(String beanName) {
		// 第二個參數設置爲true表示:允許早期依賴
		return getSingleton(beanName, true);
	}

它又調用了getSingleton(beanName, true)方法

	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		// 檢查緩存singletonObjects中是否存在beanName的實例
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				//	如果此Bean正在加載則不處理
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}
  • singletonObjects:用於保存beanNamebean實例之間的關係
  • singletonFactories:用於保存beanName和創建bean工廠之間的關係
  • earlySingletonObjects:用於保存beanNamebean實例之間的關係,與singletonObjects不同之處在於:當一個單利bean被放到這裏面之後,那麼當bean還在創建過程種,就可以通過getBean方法獲取到了,目的是用來檢查循環依賴。
  • registeredSingletons:用於保存當前所有已經創建的bean

2.3.3 【功能五】markBeanAsCreated

走到這一步說明緩存中沒有beanName的單例,所以下面要開始創建Bean了,那麼在創建之前,我們需要將即將創建的Bean加入到beanFactoryalreadyCreated屬性中。

	protected void markBeanAsCreated(String beanName) {
		if (!this.alreadyCreated.contains(beanName)) {
			synchronized (this.mergedBeanDefinitions) {
				if (!this.alreadyCreated.contains(beanName)) {
					// 將RootBeanDefinition的re-merge屬性設置爲true
					// 因爲我們要創建這個bean了,所以以放在創建過程中它的metadata發生變化
					clearMergedBeanDefinition(beanName);
					this.alreadyCreated.add(beanName);
				}
			}
		}
	}

三、總結

doGetBean方法的工作流程:

在這裏插入圖片描述

doGetBean方法是爲了獲取bean,首先從緩存中獲取,緩存中沒有就開始創建Bean,而本篇文章只講到了從緩存中獲取,下一篇文章講解重頭戲,

  • getSingleton -> createBean來創建Bean
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章