本次我们通过源码介绍ApplicationContext容器初始化流程,主要介绍容器内bean的实例化和初始化过程。ApplicationContext是Spring推出的先进Ioc容器,它继承了旧版本Ioc容器BeanFactory,并进一步扩展了容器的功能,增加了bean的自动识别、自动初始化等功能,同时引入了BeanFactoryPostProcessor、BeanPostProcessor等逻辑处理组件,目前我们使用的spring项目大部分都是基于ApplicationContext容器的。ApplicationContext容器在启动阶段便会调用所有bean的构建方法getBean(),所以当项目启动好后,容器内所有对象都已被构建好了。
“我个人习惯”将spring容器启动分为三个阶段:(1)容器初始化阶段、(2)Bean实例化(instantiation)阶段、(3)Bean初始化(initialization)阶段。
- 容器初始化阶段:这个阶段主要是通过某些工具类加载Configuration MetaData,并将相关信息解析成BeanDefinition注册到BeanDefinitionRegistry中,即对象管理信息的收集。同时也会进行各种处理器的注册、上下文的初始化、事件广播的初始化等等准备工作。
- Bean实例化(instantiation)阶段:这个阶段主要是Bean的实例化,其实就是Bean对象的构造。不过此时构造出的对象,他们内部的依赖对象仍然没有注入,只是通过反射(或Cglib)生成了具体对象的实例(执行构造函数),其实有点类似于我们手动new对象,new出的对象已经执行过了构造函数,并且内部的基本数据也已经准备好了,但如果内部还有其他对象的依赖,就需要后续的流程去主动注入。
- Bean初始化(initialization)阶段:这个阶段主要是对实例化好后的Bean进行依赖注入的过程。同时还会执行用户自定义的一些初始化方法,注册Bean的销毁方法、缓存初始化好的Bean等。
接下来我们主要围绕这三个阶段通过Spring源码来看容器初始化的具体过程(SpringBoot项目)。
一.容器初始化阶段
ApplicationContext在容器启动时会自动帮我们构建好所有的Bean,所以当我们项目启动好后,容器内所有对象都已经构建好了。其主要的逻辑都在refresh()函数中,所以我们也从这个函数开始看,下面是refresh()的主体逻辑。
我们简单介绍下几个重要函数:
- prepareRefresh():
初始化上下文环境,对系统的环境变量或者系统属性进行准备和校验,如环境变量中必须设置某个值才能运行,否则不能运行,这个时候可以在这里加这个校验,重写initPropertySources方法就好了。 - postProcessBeanFactory()、invokeBeanFactoryPostProcessors():
spring提供了一种叫做BeanFactoryPostProcessor的容器扩展机制,这种机制可以让我们在Bean实例化前,对注册到容器的BeanDefinition所保存的信息进行修改。上面两个函数就主要是BeanFactoryPostProcessor的相关操作。值得一提的是我们经常会在properties文件中配置一些属性值,然后通过${}的占位符去替换xml中的一些变量,这个过程就是BeanFactoryPostProcessor帮我实现的。 - registerBeanPostProcessors:
注册BeanPostProcessor。BeanPostProcessor应该是大名鼎鼎的了,它和BeanFactoryPostProcessor相对应,BeanFactoryPostProcessor主要是对BeanDefinition进行相关操作,而BeanPostProcessor主要是插手Bean的构建过程。BeanPostProcessor是个接口,它有很多实现类,接下来我们会逐渐接触到BeanPostProcessor的不同实现类。 - finishBeanFactoryInitialization:
初始化剩下的单例Bean(非延迟加载的)。上面的函数中构建了各种系统使用的Bean,而剩下的Bean都会在finishBeanFactoryInitialization中构建,这其中就包括我们在应用中声明的各种业务Bean,Bean的实例化和初始化过程逻辑都在这个函数中。
我想特别介绍下invokeBeanFactoryPostProcessors(beanFactory),我们都知道Spring会帮我们自动扫描出所有我们需要放入容器的Bean,其具体的实现就在这里。里面会执行所有的BeanFactoryPostProcessors,Spring帮我们定义了一个ConfigurationClassPostProcessor,它的函数postProcessBeanDefinitionRegistry会在这个阶段被执行,里面会根据我们配置的scanning-path把我们所有使用注解(@Component、@Service等…)注释的Bean解析成BeanDefinition,并记录Bean的信息到容器中。
Spring容器的启动阶段就介绍到这里,因为具体的逻辑实在实在太繁杂,而我也就知道个梗概,有想要想要详细了解的同学,可以一个一个方法的去学习了解下。接下来是我们本文的重点内容:bean的实例化和初始化过程。
二.Bean的实例化和初始化
大家总是会错误的理解Bean的“实例化”和“初始化”过程,总会以为初始化就是对象执行构造函数生成对象实例的过程,其实不然,在初始化阶段实际对象已经实例化出来了,初始化阶段进行的是依赖的注入和执行一些用户自定义的初始化逻辑。对于Bean的构建过程,网上有个非常经典的流程图如下:
上面的流程图并不是十分准确,但却把整个bean的构建、使用、销毁流程整体勾勒出来了,大家可以有个初步的整体的印象。实际上Bean的构建流程非常复杂,下面会从源码角度讲解,内容会很多也很庞杂,我把重要的方法和逻辑做了一个简单的总结,让大家可以从方法角度有个整体了解,接下来我们就开始从bean的实例化流程开始讲起。
(1)Bean的实例化
我们接着上面从finishBeanFactoryInitialization函数看起,因为我们定义的业务Bean实例化和初始化都是在这个函数中实现的。我们进入finishBeanFactoryInitialization函数内部。其中大部分的函数是Bean构建的准备逻辑,实际的构建逻辑在preInstantiateSingletons中,我们继续往下,看preInstantiateSingletons函数。
函数会先获取所有需要构建的Bean名称,之前提过在Spring容器启动阶段Bean的相关信息就会被封装成BeanDefinition并注册到容器中。通过bean的RootBeanDefinition判断该bean是否为可构建的类型,很明显可构建的Bean不能是抽象类,不能是接口,也不能是懒加载的bean。之后会判断对象是不是FactoryBean,FactoryBean是一种特殊的Bean,需要特殊处理。
FactoryBean简介
在我们平时的开发中经常会使用第三方库相关类,为了避免接口和实现类的耦合,我们通常会使用工厂模式。提供一个工厂类来实例化具体接口实现类。主体对象只需要注入工厂类,具体接口实现类有变更时,我们只需变更工厂类,而主体类无需做任何改动。针对上面的场景,spring为我们提供了更方便的工具FactoryBean,当某些第三方库不能直接注册到spring容器时,就可以实现org.springframework.beans.factory.FactoryBean接口,给出自己的对象实例化逻辑。
针对FactoryBean而言,其主语是Bean,定语为Factory,它本身也只是一个bean而已,只不过这种类型的bean本身就是用来生产对象的工厂。下面是FactoryBean接口代码,FactoryBean只定义了三个方法,getObject()返回我们需要生产的对象, getObjectType()返回生产对象的类型,isSingleton()用于标识该对象是否以单例形式存在于容器中。当我们从容器中获取FactoryBean类型的Bean时,容器返回的是FactoryBean所“生产”的对象类型,而非FactoryBean实现本身。
public interface FactoryBean {
T getObject();
Class<?> getObjectType();
default boolean isSingleton();
}
然后我们进入getBean(beanName),我们的业务Bean就是通过这个函数构建的。
经过一次跳转后我们来到了org.springframework.beans.factory.support.AbstractBeanFactory#doGetBean函数,这个函数还是蛮重要的,接下来我们详细介绍下:
在函数内首先会将传递进来的name通过transformedBeanName()函数转换成了beanName,这个函数主要有两个功能:1: 特殊处理FactoryBean的名称、2: 解决别名的问题。
之后我们会看见getSingleton(beanName)函数,这个函数灰常重要,它是用来解决循环依赖的。举个例子:有两个Bean A和B,这两个Bean间存在相互依赖。那么当容器构建A时,实例化好A后,容器会把尚未注入依赖的A暂时放入缓存中,然后去帮A注入依赖。这时容器发现A依赖于B,但是B还没有构建好,那么就会先去构建B。容器在实例化好B时,同样需要帮B注入依赖,此时B发现自己依赖A,在获取A时就可以通过getSingleton(beanName)获取尚未注入依赖的A引用,这样就不会阻塞B的构建,B完成构建后就又可以注入到A中,这样就解决了简单的循环依赖问题。当然循环依赖的问题场景很多,出现的情景也不同,上面举的例子只是最简单的一种,后面会对常见的循环依赖问题进行总结。
在之后会通过isPrototypeCurrentlyInCreation(beanName)检测Prototype类型的Bean是否已经正在构建。说到这里,我们首先需要明确的一点是:Prototype类型Bean不支持循环引用 (包括自用引用),而Singleton类型的bean是可以循环引用的 (包括自用引用),这里说的自我引用指的是自己注入自己。其实原因也不难理解,因为Prototype类型的bean是即取即用的,容器不会维护它的生命周期,更不会保存它的引用,那么就不会像Singleton类型的bean一样,在容器中有一份缓存,其实Prototype类型bean也完全没必要有缓存,毕竟容器无需维护它的生命周期。
那么代码执行到这里一但发现Prototype类型的bean已经在构建了,便说明出现了循环引用,便直接抛出异常。举个小荔枝如下:
在spring容器中会根据bean定义的scope来创建实例对象,其中我们比较常用的scope定义有两种即:singleton和prototype。
- singleton:
标记为singleton的bean在容器中只存在一个实例,所有对该对象的引用将共享这个实例。该实例从容器启动构建好后,就一直存活到容器退出,与容器“几乎”拥有相同的“寿命”。- prototype:
容器在接收到该类型对象的请求时,会每次都重新生成一个新的对象实例给请求方。当容器将对象实例返回给请求方后,容器就不再拥有当前返回对象的引用,请求方需要自己负责该对象后续生命周期的管理。有点类似于我们使用new创建对象,但区别在于我们用new创建的对像无法进行依赖注入,需要我们手动注入依赖,而prototype类型bean的实例化和依赖注入容器都会帮我们处理。有一点值得注意的是:当一个单例类型的bean引用一个prototype类型的bean时,prototype类型的bean也会变成单例。这主要是因为单例bean的依赖注入只会在容器启动时执行一次。如果要解决这个问题,可以改为手动调用getBean方法,也可以使用@lookup注解。
再接下来的逻辑其实就比较清晰了,首先获取Bean的定义信息,然后判断下是否有DependsOn依赖的Bean,没错这里就是@DependsOn注解发挥作用的地方,如果我们的Bean在构建前必须要保证某个Bean已经构建好,那么我们就可以使用这个@DependsOn这个注解。我们可以看到实现逻辑其实很简单,就是取出所有依赖的Bean,然后逐个调用getBean接口依次构建。在处理好依赖的Bean后,容器会根据Bean的类型进行构建,Bean主要有Singleton和Prototype两种类型,当然还有很多我们不常用的类型,这里我们就不管了。因为一般我们使用的Bean都是Singleton类型的,所以我们就直接看Singleton类型bean的构建方法。
我们可以看到singleton类型bean的构建调用了DefaultSingletonBeanRegistry实现的getSingleton方法。该方法有两个参数,第一个为bean的名字beanName,第二个为ObjectFactory<?> singletonFactory,是一个函数式接口,该函数式接口之后会在getSingleton方法中使用,该函数式接口的主要实现是createBean方法。
下面是DefaultSingletonBeanRegistry#getSingleton函数的实现代码,其核心的四个函数为:
// 前置检查,通过构建中bean集合(singletonsCurrentlyInCreation)来检测该bean是否进行了重复构建,
// 可以防止构造器注入可能导致的循环引用问题
beforeSingletonCreation(beanName);
// 调用函数式接口ObjectFactory的具体实现逻辑,即上文中getSingleton方法的第二个参数,主要实现就是createBean方法
singletonFactory.getObject();
// 后置处理,将当前bean从构建中bean集合(singletonsCurrentlyInCreation)中移除。
afterSingletonCreation(beanName);
// 把结果存在singletonObjects中,并删除一些用于处理循环引用的中间状态
addSingleton(beanName, singletonObject);
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(beanName, "Bean name must not be null");
synchronized (this.singletonObjects) {
// 查看单例bean是否已经构建好,凡是构建好的单例bean,都会存在Map<String, Object> singletonObjects里面
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null) {
// this.singletonsCurrentlyInDestruction是个boolean类型,记录的是当前这个单例bean是否正在被销毁,
// 如果是true,代表单例bean已经执行了自身的destroy销毁方法,或者有异常的时候执行了destroySingleton方法等情况
if (this.singletonsCurrentlyInDestruction) {
throw new BeanCreationNotAllowedException(beanName,
"Singleton bean creation not allowed while singletons of this factory are in destruction " +
"(Do not request a bean from a BeanFactory in a destroy method implementation!)");
}
if (logger.isDebugEnabled()) {
logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
}
// 前置检查,通过构建中bean集合(singletonsCurrentlyInCreation)来检测该bean是否进行了重复构建,
// 可以防止构造器注入可能导致的循环引用问题
beforeSingletonCreation(beanName);
boolean newSingleton = false;
// this.suppressedExceptions是个Set,这个Set里面存放着各种异常信息
boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
// 如果此时suppressedExceptions为空,就new LinkedHashSet<>()来保存接下来可能发生的异常
if (recordSuppressedExceptions) {
this.suppressedExceptions = new LinkedHashSet<>();
}
try {
// 调用ObjectFactory函数式方法
singletonObject = singletonFactory.getObject();
newSingleton = true;
}
catch (IllegalStateException ex) {
// 看这个时候单例是否已经被创建了,如果是的话,不报错,继续执行
singletonObject = this.singletonObjects.get(beanName);
// 如果没有被创建,报错
if (singletonObject == null) {
throw ex;
}
}
catch (BeanCreationException ex) {
if (recordSuppressedExceptions) {
// 把出现过的异常加进去
for (Exception suppressedException : this.suppressedExceptions) {
ex.addRelatedCause(suppressedException);
}
}
throw ex;
}
finally {
if (recordSuppressedExceptions) {
this.suppressedExceptions = null;
}
// 后置处理,将当前bean从构建中bean集合(singletonsCurrentlyInCreation)中移除。
afterSingletonCreation(beanName);
}
if (newSingleton) {
// 把结果存在singletonObjects中,并删除一些中间状态
addSingleton(beanName, singletonObject);
}
}
return singletonObject;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
接下来我们进入createBean(beanName, mbd, args)函数中,具体代码如下所示:
函数内首先做了些准备工作,包括:根据设置的class属性和className解析class、对override属性进行标记和验证(这里需要注意的是Spring的配置里面根本没有override-method之类的配置,但是在spring配置中存在lookup-method和replace-method,这两个配置会被统一存放在beanDefinition中的methodOverrides属性里,这个方法就是对这两个配置做操作)。在这之后会执行resolveBeforeInstantiation函数,千万不要被它上面的注释误导了,这个函数并不是用来生成我们 “通常意义” 上的动态代理的,我们 “通常意义” 上的动态代理实现在后面会有介绍。
我们可以看到resolveBeforeInstantiation里面实际上调用了applyBeanPostProcessorsBeforeInstantiation接口,在该接口里面会执行所有InstantiationAwareBeanPostProcessor的postProcessBeforeInstantiation方法。
在这我们先介绍下InstantiationAwareBeanPostProcessor,大家应该都知道BeanPostProcessor接口,这个接口作用于Bean的构建过程,可以对Bean进行一些自定义的修改,比如属性值的修改、构造器的选择等等。而InstantiationAwareBeanPostProcessor接口继承自BeanPostProcessor接口。新增了3个方法,其类图如下:
通过名字我们就可以知道,新增的3个接口中前两个分别作用于Bean实例化前和实例化后,最后一个接口postProcessPropertyValues作用于Bean的初始化阶段,主要用来设置对象属性(依赖注入),其中我们最常用的注入依赖对象的@Autowired注解,就是通过实现这个接口来进行依赖注入的。
我们接着介绍applyBeanPostProcessorsBeforeInstantiation方法,我们可以看到该方法会找到所有InstantiationAwareBeanPostProcessor类型的BeanPostProcessor,然后调用其实现的postProcessBeforeInstantiation的方法。我们最常见的该方法的一个实现类是AbstractAutoProxyCreator,我们看下其具体实现:
这里shouldSkip(beanClass, beanName)方法是一个很容易忽略的方法,但这个方法第一次被调用时把所有的切面(Advisor)加载完成。另外我们可以看到,如果我们有自定义的TargetSource,那么在这里就会直接创建代理对象。postProcessBeforeInstantiation()返回对象后,会对该对象执行所有BeanPostProcessor的postProcessorAfterInitialization()方法,最后直接返回对象给用户。
TargetSource相当于代理中目标对象的容器。当方法调用穿过所有切面逻辑,到达调用链的终点时,本该调用目标对象的方法了。但此时Spring AOP做了点手脚,他并不是直接调用这个目标对象的方法,而是需要通过TargetSource的getTarget()方法获取目标对象,然后再调用目标对象的相应方法。这种方式使得TargetSource拥有了目标对象的控制权,可以控制每次方法调用实际作用到的具体对象实例。
我们继续往下走进入doCreateBean(beanName, mbdToUse, args)方法。在spring里有个有意思的现象:大部分核心功能的实际实现函数都是以do开头的。现在我们走到了doCreateBean函数,通过名字我们就可以知道该函数用来构建Bean,而实际上Bean实例化和初始化的核心逻辑都在doCreateBean方法中,所以接下来的所有讲解都是围绕doCreateBean方法进行的。
/** * Actually create the specified bean. Pre-creation processing has already happened * at this point, e.g. checking {@code postProcessBeforeInstantiation} callbacks. * <p>Differentiates between default bean instantiation, use of a * factory method, and autowiring a constructor. * @param beanName the name of the bean * @param mbd the merged bean definition for the bean * @param args explicit arguments to use for constructor or factory method invocation * @return a new instance of the bean * @throws BeanCreationException if the bean could not be created * @see #instantiateBean * @see #instantiateUsingFactoryMethod * @see #autowireConstructor */ protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) throws BeanCreationException {
<span class="token comment">// Instantiate the bean.</span> <span class="token class-name">BeanWrapper</span> instanceWrapper <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>mbd<span class="token punctuation">.</span><span class="token function">isSingleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token comment">// 用于处理factoryBean</span> instanceWrapper <span class="token operator">=</span> <span class="token keyword">this</span><span class="token punctuation">.</span>factoryBeanInstanceCache<span class="token punctuation">.</span><span class="token keyword">remove</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>instanceWrapper <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> instanceWrapper <span class="token operator">=</span> <span class="token function">createBeanInstance</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> mbd<span class="token punctuation">,</span> args<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> final <span class="token class-name">Object</span> bean <span class="token operator">=</span> instanceWrapper<span class="token punctuation">.</span><span class="token function">getWrappedInstance</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> Class<span class="token operator"><</span><span class="token operator">?</span><span class="token operator">></span> beanType <span class="token operator">=</span> instanceWrapper<span class="token punctuation">.</span><span class="token function">getWrappedClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>beanType <span class="token operator">!=</span> NullBean<span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> mbd<span class="token punctuation">.</span>resolvedTargetType <span class="token operator">=</span> beanType<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Allow post-processors to modify the merged bean definition.</span> synchronized <span class="token punctuation">(</span>mbd<span class="token punctuation">.</span>postProcessingLock<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>mbd<span class="token punctuation">.</span>postProcessed<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">try</span> <span class="token punctuation">{<!-- --></span> <span class="token function">applyMergedBeanDefinitionPostProcessors</span><span class="token punctuation">(</span>mbd<span class="token punctuation">,</span> beanType<span class="token punctuation">,</span> beanName<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Throwable</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">BeanCreationException</span><span class="token punctuation">(</span>mbd<span class="token punctuation">.</span><span class="token function">getResourceDescription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanName<span class="token punctuation">,</span> <span class="token string">"Post-processing of merged bean definition failed"</span><span class="token punctuation">,</span> ex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> mbd<span class="token punctuation">.</span>postProcessed <span class="token operator">=</span> <span class="token keyword">true</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// Eagerly cache singletons to be able to resolve circular references</span> <span class="token comment">// even when triggered by lifecycle interfaces like BeanFactoryAware.</span> boolean earlySingletonExposure <span class="token operator">=</span> <span class="token punctuation">(</span>mbd<span class="token punctuation">.</span><span class="token function">isSingleton</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">&&</span> <span class="token keyword">this</span><span class="token punctuation">.</span>allowCircularReferences <span class="token operator">&&</span> <span class="token function">isSingletonCurrentlyInCreation</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>earlySingletonExposure<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">if</span> <span class="token punctuation">(</span>logger<span class="token punctuation">.</span><span class="token function">isTraceEnabled</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> logger<span class="token punctuation">.</span><span class="token function">trace</span><span class="token punctuation">(</span><span class="token string">"Eagerly caching bean '"</span> <span class="token operator">+</span> beanName <span class="token operator">+</span> <span class="token string">"' to allow for resolving potential circular references"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token function">addSingletonFactory</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> <span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">-</span><span class="token operator">></span> <span class="token function">getEarlyBeanReference</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> mbd<span class="token punctuation">,</span> bean<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token comment">// Initialize the bean instance.</span> <span class="token class-name">Object</span> exposedObject <span class="token operator">=</span> bean<span class="token punctuation">;</span> <span class="token keyword">try</span> <span class="token punctuation">{<!-- --></span> <span class="token function">populateBean</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> mbd<span class="token punctuation">,</span> instanceWrapper<span class="token punctuation">)</span><span class="token punctuation">;</span> exposedObject <span class="token operator">=</span> <span class="token function">initializeBean</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> exposedObject<span class="token punctuation">,</span> mbd<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Throwable</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">if</span> <span class="token punctuation">(</span>ex instanceof BeanCreationException <span class="token operator">&&</span> beanName<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token punctuation">(</span>BeanCreationException<span class="token punctuation">)</span> ex<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getBeanName</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">throw</span> <span class="token punctuation">(</span>BeanCreationException<span class="token punctuation">)</span> ex<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">BeanCreationException</span><span class="token punctuation">(</span> mbd<span class="token punctuation">.</span><span class="token function">getResourceDescription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanName<span class="token punctuation">,</span> <span class="token string">"Initialization of bean failed"</span><span class="token punctuation">,</span> ex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>earlySingletonExposure<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token class-name">Object</span> earlySingletonReference <span class="token operator">=</span> <span class="token function">getSingleton</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> <span class="token keyword">false</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>earlySingletonReference <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">if</span> <span class="token punctuation">(</span>exposedObject <span class="token operator">==</span> bean<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> exposedObject <span class="token operator">=</span> earlySingletonReference<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">this</span><span class="token punctuation">.</span>allowRawInjectionDespiteWrapping <span class="token operator">&&</span> <span class="token function">hasDependentBean</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> String<span class="token punctuation">[</span><span class="token punctuation">]</span> dependentBeans <span class="token operator">=</span> <span class="token function">getDependentBeans</span><span class="token punctuation">(</span>beanName<span class="token punctuation">)</span><span class="token punctuation">;</span> Set<span class="token operator"><</span>String<span class="token operator">></span> actualDependentBeans <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">LinkedHashSet</span><span class="token operator"><</span><span class="token operator">></span><span class="token punctuation">(</span>dependentBeans<span class="token punctuation">.</span>length<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> dependentBean <span class="token punctuation">:</span> dependentBeans<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token function">removeSingletonIfCreatedForTypeCheckOnly</span><span class="token punctuation">(</span>dependentBean<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> actualDependentBeans<span class="token punctuation">.</span><span class="token keyword">add</span><span class="token punctuation">(</span>dependentBean<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>actualDependentBeans<span class="token punctuation">.</span><span class="token function">isEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">BeanCurrentlyInCreationException</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> <span class="token string">"Bean with name '"</span> <span class="token operator">+</span> beanName <span class="token operator">+</span> <span class="token string">"' has been injected into other beans ["</span> <span class="token operator">+</span> StringUtils<span class="token punctuation">.</span><span class="token function">collectionToCommaDelimitedString</span><span class="token punctuation">(</span>actualDependentBeans<span class="token punctuation">)</span> <span class="token operator">+</span> <span class="token string">"] in its raw version as part of a circular reference, but has eventually been "</span> <span class="token operator">+</span> <span class="token string">"wrapped. This means that said other beans do not use the final version of the "</span> <span class="token operator">+</span> <span class="token string">"bean. This is often the result of over-eager type matching - consider using "</span> <span class="token operator">+</span> <span class="token string">"'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token comment">// Register bean as disposable.</span> <span class="token keyword">try</span> <span class="token punctuation">{<!-- --></span> <span class="token function">registerDisposableBeanIfNecessary</span><span class="token punctuation">(</span>beanName<span class="token punctuation">,</span> bean<span class="token punctuation">,</span> mbd<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">BeanDefinitionValidationException</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">BeanCreationException</span><span class="token punctuation">(</span> mbd<span class="token punctuation">.</span><span class="token function">getResourceDescription</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> beanName<span class="token punctuation">,</span> <span class="token string">"Invalid destruction signature"</span><span class="token punctuation">,</span> ex<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">return</span> exposedObject<span class="token punctuation">;</span> <span class="token punctuation">}</span>
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16