1. 背景
Spring框架本身非常龐大,源碼閱讀可以從Spring IOC容器的實現開始一點點了解。然而即便是IOC容器,代碼仍然是非常多,短時間內全部精讀完並不現實
本文分析比較淺,而完整的IOC創建bean實際上是非常復雜的。本文對於BeanDefinition的加載解析,bean實例化的反射調用細節不作介紹,僅以較為粗略的角度來大體感受IOC容器創建bean的過程。
本文涉及的Spring源碼版本為4.3.5.RELEASE。
2. 想要了解什么
下面就拋出幾個想要了解的問題,也是本文介紹所要圍繞的關鍵點。
- BeanFactory和ApplicationContext的區別
- IOC容器創建Bean的大致過程
- Bean的循環依賴是如何解決的
- 那些Aware究竟是什么
3. 從源碼中找出問題的答案
3.1 BeanFactory & ApplicationContext
3.1.1 BeanFactory體系
org.springframework.beans.factory.BeanFactory是Spring的Bean容器的一個非常基本的接口,位於spring-beans模塊。它包括了各種getBean方法,如通過名稱、類型、參數等,試圖從Bean容器中返回一個Bean實例。還包括諸如containsBean, isSingleton, isPrototype等方法判斷Bean容器中是否存在某個Bean或是判斷Bean是否為單例/原型等等。
可以看到BeanFactory向下主要有三條繼承路線
- ListableBeanFactory
在BeanFactory基礎上,支持對Bean容器中Bean的枚舉。 - HierarchicalBeanFactory -> ConfigurableBeanFactory
HierarchicalBeanFactory有個getParentBeanFactory方法,使得Bean容器具有親緣關系。而ConfigurableBeanFactory則是對BeanFactory的一系列配置功能提供了支持。 - AutowireCapableBeanFactory
提供了一系列用於自動裝配Bean的方法,用戶代碼比較少用到,更多是作為Spring內部使用。
3.1.2 ApplicationContext體系
org.springframework.context.ApplicationContext是Spring上下文的底層接口,位於spring-context模塊。它可以視作是Spring IOC容器的一種高級形式,也是我們用Spring企業開發時必然會用到的接口,它含有許多面向框架的特性,也對應用環境作了適配。
從上面的圖中,我們可以看到ApplicationContext作為BeanFactory的子接口,與BeanFactory之間也是通過HierarchicalBeanFactory與ListableBeanFactory橋接的。
ApplicationContext接口,繼承了MessageSource, ResourceLoader, ApplicationEventPublisher接口,以BeanFactory為主線添加了許多高級容器特性。
3.2 Spring創建Bean的大致過程
搞清楚整個Spring IOC容器創建Bean的過程,對於閱讀源碼的效率會有很大的提升。
下面梳理一下整個過程:
- 實例化BeanFactoryPostProcessor實現類
- 調用BeanFactoryPostProcessor#postProcessBeanFactory
- 實例化BeanPostProcessor實現類
- 調用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation
- 實例化Bean
- 調用InstantiationAwareBeanProcessor#postProcessAfterInstantiation
- 調用InstantiationAwareBeanPostProcessor#postProcessPropertyValues
- 為Bean注入屬性
- 調用BeanNameAware#setBeanName
- 調用BeanClassLoaderAware#setBeanClassLoader
- 調用BeanFactoryAware#setBeanFactory
- 調用BeanPostProcessor#postProcessBeforeInitialization
- 調用InitializingBean#afterPropertiesSet
- 調用Bean的init-method
- 調用BeanPostProcessor#postProcessAfterInitialization
3.3 IOC容器依賴注入
完整來說,IOC容器的初始化過程中做了在容器中建立BeanDefinition的數據映射。之后所有的依賴的注入都依托於已經存在的BeanDefinition,限於篇幅,此處略去對BeanDefinition的建立作介紹。直接從上下文的getBean開始看起。
在AbstractApplicationContext抽象類中有一個getBeanFactory方法用於返回一個ConfigurableListableBeanFactory,所有BeanFactory接口的方法實際上都委托給子類內部的ConfigurableListableBeanFactory實現。
我們以AnnotationConfigApplicationContext,它在被構造時,內部的beanFactory實際上是由父類GenericApplicationContext來初始化一個DefaultListableBeanFactory的。
因此我們看某個bean是如何被加載的可以從DefaultListableBeanFactory的getBean方法看起,對於DefaultListableBeanFactory而言那些getBean方法實際上在AbstractBeanFactory這一層就都已經實現了,並且都委托給了AbstractBeanFactory#doGetBean。下面就來看一下doGetBean方法。
protected <T> T doGetBean( final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
throws BeansException {
final String beanName = transformedBeanName(name);
Object bean;
/*
* 嘗試從緩存中拿取一個bean實例。
* Spring會在Bean還沒完全初始化完畢的前,通過一個ObjectFactory提前暴露出bean實例,這樣為解決循環依賴提供了遍歷。
*/
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isDebugEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.debug("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.debug("Returning cached instance of singleton bean '" + beanName + "'");
}
}
// 對FactoryBean的情況進行特殊處理。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 如果正在創建的bean為原型並且已經正在創建,這種循環依賴是無法解決的,要拋出異常。
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
// 如果該beanFactory中不包含要創建bean的beanDefinition,則嘗試從父beanFactory中尋找。
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
String nameToLookup = originalBeanName(name);
if (args != null) {
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
final RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// 有些bean是有depends-on/@DependsOn的,需要先初始化這些依賴。
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);
getBean(dep);
}
}
// 創建單例bean。
if (mbd.isSingleton()) {
/*
* 調用父類DefaultSingletonBeanRegistry的getSingleton,具體創建bean的工作實際上仍然是
* 回調參數中傳遞的ObjectFactory#getObject方法,而createBean實際上是子類AbstractAutowireCapableBeanFactory實現的。
*/
sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
destroySingleton(beanName);
throw ex;
}
}
});
// 對FactoryBean的情況進行特殊處理。
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 創建原型bean。
else if (mbd.isPrototype()) {
Object prototypeInstance = null;
try {
// 前置處理,維護prototypesCurrentlyInCreation,加入當前bean記錄。
beforePrototypeCreation(beanName);
// 委托給子類AbstractAutowireCapableBeanFactory來完成具體的創建bean工作。
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
// 后置處理,維護prototypesCurrentlyInCreation信息,刪除當前bean記錄。
afterPrototypeCreation(beanName);
}
// 對FactoryBean的情況進行特殊處理。
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
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, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
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;
}
}
// 到這里一個bean就已經創建完了,最后一步檢查類型,如果不匹配會嘗試轉換。
if (requiredType != null && bean != null && !requiredType.isAssignableFrom(bean.getClass())) {
try {
return getTypeConverter().convertIfNecessary(bean, requiredType);
}
catch (TypeMismatchException ex) {
if (logger.isDebugEnabled()) {
logger.debug("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
上面針對AbstractBeanFactory#doGetBean方法進行了源碼分析,從中我們可以看出它主要會干這幾件事情:
- 轉換beanName。
- 嘗試從緩存的單例中拿實例。
- 如果要創建的bean是原型模式,且已經在嘗試創建,這種循環依賴是無法解決的。
- 當前beanFactory不包含要創建的bean的beanDefinition,會嘗試從parentBeanFactory中獲取。
- 如果當前bean有依賴(xml的話就是有depends-on,注解的話有@DependsOn),則需要先完成那些bean的創建初始化。
- 針對scope分類討論創建。我們比較關心的就是單例,其次是原型。
- 類型檢查,並且嘗試轉換。
我們一般比較關心的就是單例bean和原型bean的創建。
在獲取單例bean時doGetBean方法會調用父類DefaultSingletonBeanRegistry#getSingleton。可以把DefaultSingletonBeanRegistry當作一個“單例bean桶”,因為它確實就是一個用來存放單例bean的桶。但是這個桶本身不關心bean到底該怎么創建,所以對於桶里還沒有的bean,它將創建bean的職責通過回調ObjectFactory#getObject來完成,而AbstractBeanFactory中傳遞給getSingleton方法的ObjectFactory#getObject的具體實現是調用createBean,這個方法是真正創建並初始化bean的方法,由子類AbstractAutowireCapableBeanFactory完成。
對於獲取原型bean則簡單多了,不用關心放到桶里緩存的事情,直接調用createBean創建就是了。
所以我們接下來通過AbstractAutowireCapableBeanFactory來看一下一個Bean具體是如何創建並初始化的。
protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
if (logger.isDebugEnabled()) {
logger.debug("Creating instance of bean '" + beanName + "'");
}
RootBeanDefinition mbdToUse = mbd;
Class<?> resolvedClass = resolveBeanClass(mbd, beanName);
if (resolvedClass != null && !mbd.hasBeanClass() && mbd.getBeanClassName() != null) {
mbdToUse = new RootBeanDefinition(mbd);
mbdToUse.setBeanClass(resolvedClass);
}
try {
mbdToUse.prepareMethodOverrides();
}
catch (BeanDefinitionValidationException ex) {
throw new BeanDefinitionStoreException(mbdToUse.getResourceDescription(),
beanName, "Validation of method overrides failed", ex);
}
try {
/*
* 在對象被實例化前,這里有一個短路邏輯,會調用InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation。
* 如果存在某個InstantiationAwareBeanPostProcessor的調用結果不為null,則形成了短路,接下來調用BeanPostProcessor#postProcessAfterInitialization。
*
* 實際上,一般Spring里默認就LazyInitTargetSourceCreator和QuickTargetSourceCreator可能會使得這里的短路生效。
* 大部分情況AOP還是在bean被正常實例化后通過調用postProcessAfterInitialization實現的。
*/
Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
if (bean != null) {
return bean;
}
}
catch (Throwable ex) {
throw new BeanCreationException(mbdToUse.getResourceDescription(), beanName,
"BeanPostProcessor before instantiation of bean failed", ex);
}
// 創建bean的主要方法。
Object beanInstance = doCreateBean(beanName, mbdToUse, args);
if (logger.isDebugEnabled()) {
logger.debug("Finished creating instance of bean '" + beanName + "'");
}
return beanInstance;
}
從上面可以看到AbstractAutowireCapableBeanFactory#createBean是創建bean的主要入口方法,但仍然不是最主要在“干活”的方法。繼續向下看doCreateBean
方法。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) throws BeanCreationException {
BeanWrapper instanceWrapper = null;
if (mbd.isSingleton()) {
// 嘗試從factoryBean緩存中獲取。
instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
}
if (instanceWrapper == null) {
// 創建bean實例。
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
final Object bean = (instanceWrapper != null ? instanceWrapper.getWrappedInstance() : null);
Class<?> beanType = (instanceWrapper != null ? instanceWrapper.getWrappedClass() : null);
synchronized (mbd.postProcessingLock) {
if (!mbd.postProcessed) {
try {
applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
}
catch (Throwable ex) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Post-processing of merged bean definition failed", ex);
}
mbd.postProcessed = true;
}
}
/*
* Spring為了解決單例bean的循環引用問題,會在bean還沒有完全初始化完畢前通過添加singletonFactory
* 使得其它bean可以拿到某個bean的實例引用。
*/
boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
isSingletonCurrentlyInCreation(beanName));
if (earlySingletonExposure) {
if (logger.isDebugEnabled()) {
logger.debug("Eagerly caching bean '" + beanName +
"' to allow for resolving potential circular references");
}
addSingletonFactory(beanName, new ObjectFactory<Object>() {
@Override
public Object getObject() throws BeansException {
return getEarlyBeanReference(beanName, mbd, bean);
}
});
}
// 接下去初始化bean。
Object exposedObject = bean;
try {
// 填充bean中的屬性。
populateBean(beanName, mbd, instanceWrapper);
if (exposedObject != null) {
/*
* 調用初始化方法,比如:
* 1. 各種aware回調
* 2. 調用BeanPostProcessor#postProcessBeforeInitialization
* 3. 調用InitializingBean#afterPropertiesSet, xml中的init-method
* 4. 調用BeanPostProcessor#postProcessAfterInitialization
*/
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
}
catch (Throwable ex) {
if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
throw (BeanCreationException) ex;
}
else {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
}
}
if (earlySingletonExposure) {
Object earlySingletonReference = getSingleton(beanName, false);
/*
* 上面的getSingleton第二個參數為false表示不會主動觸發early reference的創建。
* 所以此處earlySingletonReference只有在bean創建過程中發現有別的bean與當前bean有循環依賴才不為空。
*/
if (earlySingletonReference != null) {
/*
* 如果當前bean調用initializeBean沒有增強原始bean實例,則取earlySingletonReference。
*
* 舉例:
* BeanA與BeanB互相依賴。Srping先創建BeanA,再創建BeanB。
* BeanA通過addSingletonFactory暴露了獲取BeanA引用的途徑。
*
* 在populateBean的時候需要注入BeanB,而BeanB又需要注入BeanA,
* 則在獲取BeanA時會調用原先BeanA暴露的ObjectFactory,繼而使得earlySingletonObjects中加入了BeanA引用。
*
* 回到BeanA的創建過程,走到此步時,發現initializeBean沒有增強原始bean實例,
* 則需要取其它循環依賴bean拿BeanA時在registry留下的結果(原始bean經過SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference回調)。
*/
if (exposedObject == bean) {
exposedObject = earlySingletonReference;
}
else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
// 獲取當前bean依賴的其它bean。
String[] dependentBeans = getDependentBeans(beanName);
// 過濾篩選出真正依賴的bean。
Set<String> actualDependentBeans = new LinkedHashSet<String>(dependentBeans.length);
for (String dependentBean : dependentBeans) {
if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
actualDependentBeans.add(dependentBean);
}
}
/*
* 舉例:
* BeanA與BeanB互相依賴。Srping先創建BeanA,再創建BeanB。
* BeanA的創建走到這里時會拋出異常。
*
* 原因是上面的exposedObject != bean說明initializeBean方法的調用增強了原始的BeanA。
* 而BeanB中注入的BeanA很可能是原始beanA(可能會有SmartInstantiationAwareBeanPostProcessor#getEarlyBeanReference回調,
* 也就是BeanB中注入的BeanA不是此處BeanA的最終版exposedObject。
*/
if (!actualDependentBeans.isEmpty()) {
throw new BeanCurrentlyInCreationException(beanName,
"Bean with name '" + beanName + "' has been injected into other beans [" +
StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
"] in its raw version as part of a circular reference, but has eventually been " +
"wrapped. This means that said other beans do not use the final version of the " +
"bean. This is often the result of over-eager type matching - consider using " +
"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.");
}
}
}
}
try {
registerDisposableBeanIfNecessary(beanName, bean, mbd);
}
catch (BeanDefinitionValidationException ex) {
throw new BeanCreationException(
mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
}
return exposedObject;
}
3.4 Bean的循環依賴是如何解決的
不是所有的循環依賴Spring都能夠解決的。
-
對於最簡單的情況,bean為單例,且使用Autowired或者setter注入,Spring是可以解決這樣的循環依賴的。通過上面的代碼中我們可以看出,在一個Bean實例化后,會調用addSingletonFactory方法,在IOC容器中通過一個ObjectFactory暴露出可以獲取還未完全初始化完畢的bean引用。若存在循環依賴,則依賴的bean可以在調用getBean時通過getSingleton方法獲取到循環依賴的bean。
-
但是Spring是不允許出現原型環的,舉例來說,BeanA和BeanB循環依賴且scope都為prototype。因為prototype的bean,不會觸發addSingletonFactory,即每次get這樣的bean都會新創建一個。所以創建BeanA需要注入一個BeanB,而這個BeanB又需要注入一個新的BeanA,這樣的循環依賴是沒辦法解決的。Spring會判斷當前bean是否是prototype並且已經在創建中,然后拋出異常。
-
對於構造器依賴,可以作一下討論,下面討論的bean的scope都為單例
- 如果BeanA構造器中依賴BeanB,並且BeanA先創建,則無論BeanB以哪種形式依賴BeanA,都沒辦法解決這樣的循環依賴。因為實例化BeanA需要先得到BeanB(此時還未提前暴露引用),BeanB依賴BeanA,但是拿不到BeanA提前暴露的引用,這就形成了無限循環。這種情況會在BeanB試圖獲取BeanA時在beforeSingletonCreation方法拋出異常。
- 如果BeanA非構造器依賴BeanB,並且BeanA先創建,BeanB即使構造器依賴BeanA,也可以進行解決循環依賴。 因為這種情況BeanB可以拿到BeanA提前暴露的引用。
3.5 那些Aware究竟是什么
Spring中有很多XXXAware接口,從字面意思上很容易理解:就是bean能夠“感知”XXX。通常這些接口的方法都是setXXX。在項目里做一個工具類實現ApplicationContextAware接口,里面可以塞一個ApplicationContext實例到靜態域中,在代碼中就可以很方便獲取到Spring上下文進行一些操作。
那么Spring對於這些Aware接口是在哪一步調用的呢?答案其實在上面的源碼分析中已經提到。在AbstractAutowireCapableBeanFactory#initializeBean方法中,Spring默認會對實現BeanNameAware, BeanClassLoaderAware, BeanFactoryAware進行回調,為它們注入beanName, classLoader, beanFactory等。
而對於更多的一些擴展,Spring基於那些processor實現了很強的可拓展性與可插拔性。比如我們非常熟悉的ApplicationContextAware接口實際上是通過ApplicationContextAwareProcessor來實際調用的,它繼承了BeanPostProcessor,其中postProcessBeforeInitialization方法中會對EnvironmentAware, EmbeddedValueResolverAware, ApplicationContextAware等等一系列Aware接口的子類Bean進行回調,為其注入相關資源。
那么ApplicationContextAwareProcessor是什么時候出現在BeanPostProcessor集合中的呢?在AbstractApplicationContext#prepareBeanFactory方法中,Spring有如下代碼:
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
也就是當Spring上下文在初始化prepareBeanFactory的時候就已經添加了ApplicationContextAwareProcessor。