IOC流程解析-实例化和初始化

本次内容为解析核心方法剩下的全部内容,重点是bean 的实例化和初始化部分。对于其余IOC 部分内容感兴趣的小伙伴可以根据文章最后的导航栏直接跳跃。

源码分析

接着上篇文章(上篇文章是:[IOC流程解析-BeanFactoyPostProcessor和BeanPostProcessor](https://liwqtm.github.io/2022/03/14/Spring IOC-3/#more)),我们还是继续看IOC 的核心方法refresh 方法的内容。这次会提到两个面试常问的问题:BeanFactory 和FactoryBean 的区别、FactoryBean 和普通Bean 的区别,这个文章的最后我会细说一下,有需要面试的小伙伴可以直接跳到文章最后查看。

初始化消息源,国际化-initMessageSource方法

从上篇文章讲的registerBeanPostProcessors 方法后,这里就来到initMessageSource 方法。

initMessageSource 方法不是我们的重点,我们这里就简单描述一下其主要作用:初始化消息源,也就是国际化,目的就是为了多语言的切换,而initMessageSource 方法的执行结果就是向BeanFactory 中的单例池singletonObjects 集合添加了一个bean,一个完整的bean 对象messageSource 对象。

初始化事件广播器-initApplicationEventMulticaster方法

核心方法接着往下走,看到initApplicationEventMulticaster 方法,这个方法也同样简单,还是向BeanFactory 中的单例池singletonObjects 集合添加了一个完整的bean 对象,如果在没有配置事件广播器的情况下,默认创建的是SimpleApplicationEventMulticaster 对象。

Spring事件传播机制

这个还需要知道一个知识点:Spring事件传播机制。首先我们要知道Spring事件传播机制是参考监听者模式改造而来,正常的监听者模式为:被监听者和监听者,当被监听者发生改变时,会将改变推送给监听者。spring 在这个基础上加了一个事件广播器,由这个事件广播器来维护监听者和被监听者之间的关系,也是就将监听者放进集合列表中,然后和被监听者关系对应起来。

那么这里就有三个角色:

  • 事件监听器(ApplicationListener)

  • 事件发布者(ApplicationEventPublisher)因为ApplicationContext 实现了 ApplicationEventPublisher,所以事件发布可以直接使用ApplicationContext

  • 事件广播器(ApplicationEventMulticaster),这里系统默认创建的是SimpleApplicationEventMulticaster

除此之外还有一个就是事件本身(ApplicationEvent),当事件发布者事件广播器发布事件的时候,其实就是传输了一个ApplicationEvent 事件对象,然后由事件广播器再次传输给监听列表中的每一个事件监听器这个ApplicationEvent事件对象。

事件传播机制先说到这里。继续说核心代码。

拓展方法-onRefresh方法

onRefresh方法这个没有说的,这个就是一个空方法,可以用来自己实现一些业务逻辑的。

注册监听器-registerListeners方法

这里就是上面说的事件传播机制的监听器注册,还是向BeanFactory 中的单例池singletonObjects 集合添加了一个完整的bean 对象,同时也会获取到所有实现了ApplicationListener 接口的对象,然后添加的广播器维护的监听列表集合中,等待后续的调用。

实例化和初始化方法-finishBeanFactoryInitialization方法

终于到本次的重点了,走完了前面一系列的操作,然后到了IOC 流程图中的重点实例化和初始化bean,先回顾一下这部分的流程图。这也是IOC 流程的最后一步了。

image-20220423204948988

我们跟进finishBeanFactoryInitialization 方法,其余的代码可以不看,这里都是设置一些加载器之类的,重点看这个方法的最后一句。

1
2
// 5.实例化所有剩余(非懒加载)单例对象  重要===》
beanFactory.preInstantiateSingletons();

获取到BeanDefinition并调用getBean方法-preInstantiateSingletons方法

跟进preInstantiateSingletons 方法,首先获取的就是所有BeanDefinition 名称的集合,注意我们目前执行的代码就是在之前创建的BeanFactroy,所以这个名称集合是可以直接获取的。

1
2
// 1.创建beanDefinitionNames的副本beanNames用于后续的遍历,以允许init等方法注册新的bean定义。
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

然后遍历这个集合,用名字获取到具体的对象。

1
2
3
4
5
6
7
8
// 2.遍历beanNames,触发所有非懒加载单例bean的初始化
for (String beanName : beanNames) {

// 3.获取beanName对应的MergedBeanDefinition
/*
Merged意义在于处理bean之间的父子继承关系,处理属性继承和覆盖(如果有的话)。
*/
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);

接下就要判断是否要将对象交给spring 管理,也就是要不要将对象添加的BeanFcatory 的单例池属性中,其依据有三个:BeanDefinition 对应的Bean实例是否是抽象类、是否是单例、是否懒加载,只要其中一个条件不满足,那么当前就不会注册spring 单例池,也就说必须是非抽象类、非懒加载的单例对象spring 在启动的时候才会去注册。

1
2
// 4.bd对应的Bean实例:不是抽象类 && 是单例 && 不是懒加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {

接下来就是将这些非抽象类、非懒加载的单例对象再次分类、判断该对象是否实现了FactoryBean 接口,FactoryBean这里会单独处理一下对象名称,然后再注册其对象,注意这里不是注册FactoryBean 的getObjeck 方法返回的对象。

FactoryBean 接口注册和普通注册的方法都是同一个,主要就是beanName 做了处理,所以我们重点看getBean 方法就行。

1
2
3
4
5
6
7
8
// 5.判断beanName对应的bean是否为FactoryBean
if (isFactoryBean(beanName)) {}
else {
// 6.如果beanName对应的bean不是FactoryBean,只是普通Bean,通过beanName获取bean实例
// 调用前置后置处理器、实例化、填充、反射,都藏在这个getBean里!
//getBean---doGetBean---createBean---doCreateBean
getBean(beanName);
}

getBean->doGetBean->createBean->doCreateBean

spring 关于getBean 方法往后的调用都比较复杂,但是只跟着主流程,也就是getBean->doGetBean->createBean->doCreateBean 这一段方法逻辑走,一定不会跟丢,我们这里就简单的介绍一下前三个方法,正在的构建bean 和注册单例池还是在doCreateBean 方法里面。

首先是getBean 方法的调用,这里还是挺简单的,就是直接调用doGetBean 方法。

1
2
3
4
5
@Override
public Object getBean(String name) throws BeansException {
// 获取name对应的bean实例,如果不存在,则创建一个
return doGetBean(name, null, null, false);
}

然后是doGetBean 方法,这里代码就比较多了,我们要知道的是在这个方法里面大体做了些什么事情就行了。其主要目的就是调用createBean 方法。

  1. 判断当前对象是否已经注册到spring 的单例池中了,是则直接返回,这也是为什么单例池也叫做一级缓存的原因。
  2. 解决循环依赖,这里我们后面说循环依赖的时候再回头来看。
  3. 然后判断如果存在副容器的话,还要再去副容器中判断获取是否存在当前对象实例。
  4. 最后获取到具体的BeanDefinition 对象,然后判断该对象是否是单例,因为这里单例是一段逻辑,多例又是另一端段逻辑,不过最后都是调用createBean 方法。

接着是createBean 方法,这里的内容比较简单,最主要的就是调用doCreateBean 方法,不是我敷衍啊,真是我能力有限,我们还是看最主要的方法就行了。

真正获取完整对象的内容-doCreateBean方法

终于来到了本次的重中之重,这里也是IOC 的核心,理清楚这个流程基本上IOC 的面试就不是问题了。老规矩还是看重点,一点一点的分析。

实例化

首先就是就是bean 的实例化,这里调用的是createBeanInstance 方法。这里个方法里面的代码没有什么可以深究的,就是通过反射获取到对应的实例对象,注意第一重点:这里实例出的对象是没有任何属性值的,就只是反射实例了一个对象而已。

1
2
3
4
5
6
7
if (instanceWrapper == null) {
// 3.【bean实例化】根据beanName、mbd、args,使用对应的策略创建Bean实例,并返回包装类BeanWrapper【关键点】!!
instanceWrapper = createBeanInstance(beanName, mbd, args); // ===> 反射来创建实例
}

// 4.拿到创建好的Bean实例,这里已经实例化完成! 相当于new出来了
Object bean = instanceWrapper.getWrappedInstance();
初始化

然后看第二个重点:bean 的初始化。这里是两段代码调用,首先就是属性的注入,然后是bean 的初始化,主要属性注入是属于初始化的流程中,不是实例化的,这里区分开是为了后面对于循环依赖的理解和解决。

1
2
3
4
5
// 9.【属性注入】对bean进行属性填充;其中,可能存在依赖于其他bean的属性,则会递归初始化依赖的bean实例
populateBean(beanName, mbd, instanceWrapper); // ===> instanceWrapper藏着我们的bean,给他灌属性

// 10.【bean初始化】(回调Bean的后置处理器等..)!
exposedObject = initializeBean(beanName, exposedObject, mbd); // ====》
属性注入

首先跟进populateBean 方法。

这里我们直接看重点,方法中的最后一句话。上面全部都是一些校验之类的,我们暂时不关注。

1
2
// 真正的注入在这里!!将属性注入到bean实例当中,这才是真正的属性赋值的地方【关键点】
applyPropertyValues(beanName, mbd, bw, pvs);

继续跟进applyPropertyValues 方法。

这里我们找到resolveValueIfNecessary 方法的调用,上面的内容都是获取当前对象需要赋值的属性和为了构建valueResolver 解析器对象,判断了一些是否是注解方式注入、set注入之类的,然后构建出具体的解析器对象,我们重点看resolveValueIfNecessary 方法。

1
2
3
4
/*
* 【重点】使用解析器解析不同类型的值(包括循环依赖的解决)
*/
Object resolvedValue = valueResolver.resolveValueIfNecessary(pv, originalValue);

继续跟进resolveValueIfNecessary 方法。

到了这里就是判断当前需要注入的属性,属于哪个类型,然后再调用具体的赋值方法,这里就不重点看了,后面将循环依赖的时候,我们再回头来看其中对于对象注入的具体方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 7. 解析List
else if (value instanceof ManagedList) {
// May need to resolve contained runtime references.
return resolveManagedList(argName, (List<?>) value);
}
// 8. 解析Set
else if (value instanceof ManagedSet) {
// May need to resolve contained runtime references.
return resolveManagedSet(argName, (Set<?>) value);
}
// 9. 解析Map
else if (value instanceof ManagedMap) {
// May need to resolve contained runtime references.
return resolveManagedMap(argName, (Map<?, ?>) value);
}
激活所有Aware方法

然后跟进initializeBean 方法。

这里可以看到首先就是激活所有Aware 方法,这里就是判断当前对象是否实现了BeanNameAware、BeanClassLoaderAware、BeanFactoryAware 接口,然后将对应的对应的setBeanName、setBeanClassLoader、setBeanFactory 方法里面塞值。

1
2
3
4
5
6
7
8
9
10
11
12
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 1.激活Aware方法
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
}
else {
// 如果 bean 实现了 BeanNameAware、BeanClassLoaderAware 或 BeanFactoryAware 接口,回调
invokeAwareMethods(beanName, bean);
}
加载的所有Bean的后置处理器的Before方法

接下来就是调用我们之前加载的所有Bean 的后置处理器的Before 方法,这里我是上篇文章说过的IOC流程解析-BeanFactoyPostProcessor和BeanPostProcessor,这里的调用也很简单,就说在BeanFactory 中获取BeanPostProcessor 集合,然后迭代调用即可。

1
2
3
4
5
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
// 2.在初始化前应用BeanPostProcessor的postProcessBeforeInitialization方法,允许对bean实例进行包装
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
throws BeansException {

Object result = existingBean;
// 1.遍历所有注册的BeanPostProcessor实现类,调用postProcessBeforeInitialization方法
for (BeanPostProcessor processor : getBeanPostProcessors()) {
// 2.在bean初始化方法执行前,调用postProcessBeforeInitialization方法
Object current = processor.postProcessBeforeInitialization(result, beanName);
if (current == null) {
return result;
}
result = current;
}
return result;
}
执行InitializingBean接口初始化方法和自定义初始化方法

继续就到了invokeInitMethods 初始化方法,这一步就是判断bean 配置信息标签中是否设置了init-method 属性,如果是则执行设置的自定义初始化方法,或者判断bean 是都实现了InitializingBean 接口,如果是则调用其afterPropertiesSet 方法。注意是走的InitializingBean 接口,然后再走的自定义方法。

1
2
3
4
5
6
7
8
9
10

try {
// 3.调用初始化方法( 处理 bean 中定义的 init-method,或者如果 bean 实现了 InitializingBean 接口,调用 afterPropertiesSet() 方法)
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
调用所有BeanPostProcessor后置处理器的After方法

然后就是最后调用所有BeanPostProcessor 后置处理器的After 方法,这里依然是迭代调用,跟上面的Before 方法没有区别。最后返回初始化完成结果。

1
2
3
4
5
6
7
if (mbd == null || !mbd.isSynthetic()) {
// 4.在初始化后应用BeanPostProcessor的postProcessAfterInitialization方法,允许对bean实例进行包装
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}

// 5.返回wrappedBean
return wrappedBean;

这个后面的方法就可以不看了,自行了解一下就行。这个方法执行完成之后,我们就得到了一个完整的bean 对象,然后我们回到doGetBean 方法,这里有一个很有意思的地方,刚刚忘记说了,createBean 方法本身不是在doGetBean 方法中调用的,我们再看下具体代码。

完整对象注入单例池

注意这里的意思是:调用getSingleton 方法,并传入一个beanName和一个函数。也就是说doGetBean 方法调用的是getSingleton 方法,而不是doGetBean 方法,当然最后还是调用doGetBean 方法,我们上面的思路是没有错的,就是在中间加一步。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 9.1 scope为singleton的bean创建(新建了一个ObjectFactory,并且重写了getObject方法)
sharedInstance = getSingleton(beanName, () -> {
try {
// 9.1.1 创建Bean实例 ===》
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;
}
});

我们这里跟进getSingleton 方法,首先加锁判避免重复创建,然后判断是否存在一级缓存中,也就是单例池中,然后做一些准备工作,最后调用我们刚刚传入函数的getObject 方法,这里回头再看其实入参就是ObjectFactory 类型对象,而我们刚刚看的函数就是getObject 方法的重写。

这里还有一个需要注意的就是在调用doCreateBean 方法之前,这里会添加一个在singletonsCurrentlyInCreation 集合属性,这里记录的就是当前Bean 正在被创建。

1
2
3
4
5
// 5.创建单例前的操作
beforeSingletonCreation(beanName);

// 6.执行singletonFactory的getObject方法获取bean实例
singletonObject = singletonFactory.getObject();
函数接口-ObjectFactory接口

这里又有一个小知识点,我自己本身也没有怎么看,用推测的吧,首先上面提到的ObjectFactory 接口,本身只有一个方法就是getObject,但是有一个由java 提供的注解@FunctionalInterface,字面理解是功能接口,我理解是函数接口,可以接收一个函数式的方法,只跟上面的实现一样。

1
2
3
4
5
@FunctionalInterface
public interface ObjectFactory<T> {

T getObject() throws BeansException;
}

那么上一步走完后,接下来就是addSingleton 方法的调用,这一步是为了将刚刚创建的对象存入单例池中。

1
2
// 8.如果是新的单例对象,将beanName和对应的bean实例添加到缓存中(singletonObjects、registeredSingletons)
addSingleton(beanName, singletonObject);
1
2
3
4
5
6
7
8
9
10
11
12
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
// 1.添加到单例对象缓存(1级缓存)
this.singletonObjects.put(beanName, singletonObject);
// 2.将单例工厂缓存移除(已经不需要)
this.singletonFactories.remove(beanName);
// 3.将早期单例对象缓存移除(已经不需要)(2级缓存)
this.earlySingletonObjects.remove(beanName);
// 4.添加到已经注册的单例对象缓存
this.registeredSingletons.add(beanName);
}
}

到这里为止IOC 实例化、初始化、注册单例池的内容基本就结束了。

发布事件与清除上下文环境-finishRefresh方法

回到refresh 核心方法,我们还有最后一步,就是发布事件并清除上下文环境,这里也很好理解,我们上面不是构建了事件广播器之类的对象嘛,这里就是用来发布事件到广播器,然后由广播器推送到监听列表中的各个监听器的,至于上下文环境之类的我们后面MVC 的内容再说。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected void finishRefresh() {
// Clear context-level resource caches (such as ASM metadata from scanning).
//清除resourceCaches资源缓存中的数据
clearResourceCaches();

// Initialize lifecycle processor for this context.
//注释1. 为此上下文初始化生命周期处理器
initLifecycleProcessor();

// Propagate refresh to lifecycle processor first.
//注释2. 首先将刷新完毕事件传播到生命周期处理器(触发isAutoStartup方法返回true的SmartLifecycle的start方法)
getLifecycleProcessor().onRefresh();

// Publish the final event.
//注释3. 推送上下文刷新完毕事件到相应的监听器
publishEvent(new ContextRefreshedEvent(this));

// Participate in LiveBeansView MBean, if active.
LiveBeansView.registerApplicationContext(this);
}

面试点:BeanFactory和FactoryBean的区别与FactoryBean和普通Bean的区别

BeanFactory和FactoryBean区别

我们先说BeanFactory 和FactoryBean 区别,这个比较简单,通过这一些的文章我们已经很了解BeanFactory 了,那我们现在只要知道FactoryBean 就行了。

FactoryBean 就是一个单纯的接口,其中有三个方法需要实现,最主要的就是getObject,可以这么说如果有对象实现了FactoryBean 接口,那么bean 获取的时候,就不再获取本身对象实例,也就是说如果A 实现了FactoryBean 接口,那么applicationContext.getBean(A) 的时候,获取到的就是可能不是A,而是FactoryBean 的getObject 方法返回的对象。

1
2
3
4
5
6
7
8
9
public interface FactoryBean<T> {

T getObject() throws Exception;

Class<?> getObjectType();

boolean isSingleton();

}

对了这里我们还可以简单看下FactoryBean 是怎么获取到对象的。还是以applicationContext.getBean(A) 来跟进调用。

跟进后发现有回到了上面说的doGetBean 方法的调用。

1
2
3
4
public Object getBean(String name) throws BeansException {
// 获取name对应的bean实例,如果不存在,则创建一个
return doGetBean(name, null, null, false);
}

其实上面注册过之后,我们就可以在单例池中拿到对应的对象实例,注意这里的实例还是A 对象的实例,然后就可以进入我们上面没有进入的判断,调用getObjectForBeanInstance 方法。

1
2
3
4
5
6
7
8
9
// 2.尝试从缓存中获取beanName对应的实例, 循环依赖闭环可以拿到
Object sharedInstance = getSingleton(beanName);

// 这里说下 args ,虽然看上去一点不重要。前面我们一路进来的时候都是 getBean(beanName),
// 所以 args 传参其实是 null 的,但是如果 args 不为空的时候,那么意味着调用方不是希望获取 Bean,而是创建 Bean
if (sharedInstance != null && args == null) {
// 3.1 返回beanName对应的实例对象(主要用于FactoryBean的特殊处理,普通Bean会直接返回sharedInstance本身)
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}

这里的方法更简单。如果不是FactoryBean 实现,直接返回,也就说普通对象,不走下面的流程,如果是则将传入的实例对象强转为FactoryBean 对象,然后getObjectFromFactoryBean 方法获取真正的返回实例对象,这个方法就是调用其getObject 方法。不过正在的调用还在里面的一层doGetObjectFromFactoryBean 方法中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
if (!(beanInstance instanceof FactoryBean)) {
return beanInstance;
}

if (object == null) {
// Return bean instance from factory.
// 3.只有beanInstance是FactoryBean才能走到这边,因此直接强转
FactoryBean<?> factory = (FactoryBean<?>) beanInstance;
// Caches object obtained from FactoryBean if it is a singleton.
if (mbd == null && containsBeanDefinition(beanName)) {
// 4.mbd为空,但是该bean的BeanDefinition在缓存中存在,则获取该bean的MergedBeanDefinition
mbd = getMergedLocalBeanDefinition(beanName);
}
// 5.mbd是否是合成的(这个字段比较复杂,mbd正常情况都不是合成的,也就是false)
boolean synthetic = (mbd != null && mbd.isSynthetic());
// 6.从FactoryBean获取对象实例
object = getObjectFromFactoryBean(factory, beanName, !synthetic);
}
// 7.返回对象实例
return object;

总结一下:BeanFactory 是Bean 的工厂,其中有单例池、BeanDefinition、BeanPostProcessor等等,而FactoryBean 是接口,只要实现了该接口那么获取其对象的时候,就是获取getObject 方法返回的对象,而不是获取对象本身实例。

FactoryBean和普通Bean的区别

其实这点刚刚也说了,它们之剑的区别就是获取对象实例的时候不一样,普通Bean 在单例池中获取到之后就返回了,而实现了FactoryBean 接口的对象还要继续走,直到最后调用getObject 方法返回才行。

总结

全文总结一下,本次说完了核心方法的全部调用,主要重点是bean 的实例化、初始化、注册等,还有一些beanPostProcessor 的两个方法调用之类的内容,再有的话就是spring 的事件传播机制了,最后也聊了一下常见的两个面试点。后续文章还是聊一下面试点:循环依赖的解决。

附录Spring 源码分析系列文章

IOC

时间 文章
2022-03-09 Spring的基本概念和IOC流程的简述
2022-03-11 IOC流程解析-BeanFactory的创建
2022-03-14 IOC流程解析-BeanFactoyPostProcessor和BeanPostProcessor
2022-03-15 IOC流程解析-实例化和初始化
2022-03-17 IOC流程解析-循环依赖

AOP

时间 文章
2022-03-19 AOP流程源码分析-配置信息解析和代理对象创建
2022-03-20 AOP流程源码分析-请求调用全流程