整体流程
要想搞清楚Spring核心代码的运作流程,其实也比较好办,那就是调试一下Spring Context的初始化过程,这个过程搞清楚了,整个Spring的核心体系也就搞清楚了。
要弄清楚这个流程,可以创建一个最最基本的spirng应用,只保留spring最核心的spring-context和spring-beans的依赖,然后进行调试,这样就能够清晰地看到spring体系加载的主线流程。
下面是一个十分精简的spring应用,应用中只有一个Bean,一个自定义的BeanPostProcess,以及一个主程序。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
package net.liwenbo.myspring;
public class Person {
private String name;
private int age;
private int gender;
public Person(String name, int age, int gender) {
this.name = name;
this.age = age;
this.gender = gender;
}
public void eat() {
System.out.println(name + " eating...");
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// SpringTest.java
package net.liwenbo.myspring;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
public class SpringTest {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringTest.class);
Person lwb = context.getBean("person", Person.class);
lwb.eat();
}
@Bean
public Person person() {
return new Person("liwenbo", 36, 1);
}
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
package net.liwenbo.myspring;
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("Invoke postProcessBeforeInitialization, bean Name = " + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Invoke postProcessAfterInitialization, bean Name = " + beanName);
return bean;
}
}
|
pom.xml
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
|
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>net.liwenbo</groupId>
<artifactId>myspring</artifactId>
<version>1.0.0-SNAPSHOT</version>
<dependencies>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.16.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.2.16.RELEASE</version>
</dependency>
</dependencies>
</project>
|
运行这个程序,可以在 postProcessBeforeInitialization 处打一个断点,这样就能很方便地看到整个初始化过程的调用堆栈了。

下图为初始化非懒加载的单例beans的时候的调用堆栈。

AbstractApplicationContext中的 refresh 方法,是整个容器初始化过程中的关键入口。这里很明显采用了模板方法模式,很多处理需要子类来自己实现。
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
|
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 准备容器刷新
prepareRefresh();
// 告诉子类去刷新内部的bean工厂
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 准备本context的beanFactory
prepareBeanFactory(beanFactory);
try {
// 允许子类中进行beanFacotry的后续处理
postProcessBeanFactory(beanFactory);
// 调用本context注册的beanFacotry的后置处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册Bean的后置处理器(BeanPostProcessor)
registerBeanPostProcessors(beanFactory);
// 初始化消息源
initMessageSource();
// 初始化应用的事件多播机制
initApplicationEventMulticaster();
// 这个是需要子类去实现的,一些在初始化过程中的特定操作
onRefresh();
// 检查并注册监听器
registerListeners();
// 初始化所有非懒加载的bean,我们的bean就是在这里创建的
// 可以看到上图里面的调用链,doCreateBean是真正创建Bean的方法
// 创建和初始化Bean的过程中,就会调用BeanPostProcessor中的方法
finishBeanFactoryInitialization(beanFactory);
// 完成刷新,调用LifecycleProcessor的onRefresh方法,发出ContextRefreshedEvent事件
finishRefresh();
}
catch (BeansException ex) {
// 有异常,处理,清理容器,代码略
...
}
finally {
// 清理Spring core里面的一些缓存,因为对于一些单例的bean,我们可能再也不需要他们的metadata了
resetCommonCaches();
}
}
}
|
Bean的创建
Bean的创建的前三个阶段:实例化、属性赋值、初始化,主要逻辑都在doCreateBean()方法中,逻辑比较清晰,就是顺序调用以下三个方法,这三个方法与三个生命周期阶段一一对应,非常重要,在后续扩展接口分析中也会涉及。
源码如下,能证明实例化,属性赋值和初始化这三个生命周期的存在。关于本文的Spring源码都将忽略无关部分,便于理解:
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
|
// Bean创建的大致过程,忽略非核心代码
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// 实例化Bean
BeanWrapper instanceWrapper = null;
if (instanceWrapper == null) {
instanceWrapper = createBeanInstance(beanName, mbd, args);
}
// 初始化Bean实例
Object exposedObject = bean;
try {
// 属性赋值
populateBean(beanName, mbd, instanceWrapper);
// 初始化Bean
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
// 其他的一些处理
....
return exposedObject;
}
|
销毁Bean阶段:
至于销毁,是在容器关闭时调用的,详见 ConfigurableApplicationContext#close()
生命周期常用扩展点
Spring生命周期相关的常用扩展点非常多,所以问题不是不知道,而是记不住或者记不牢。其实记不住的根本原因还是不够了解,这里通过源码+分类的方式帮大家记忆。
区分影响一个bean或者多个bean是从源码分析得出的。
以BeanPostProcessor为例:
-
从refresh方法来看,BeanPostProcessor 实例化比正常的bean早。
-
从initializeBean方法看,每个bean初始化前后都调用所有BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterInitialization方法。
第一大类:影响多个Bean的接口
实现了这些接口的Bean会切入到多个Bean的生命周期中。正因为如此,这些接口的功能非常强大,Spring内部扩展也经常使用这些接口,例如自动注入以及AOP的实现都和他们有关。
这两兄弟可能是Spring扩展中最重要的两个接口,InstantiationAwareBeanPostProcessor作用于实例化阶段的前后,BeanPostProcessor 作用于初始化阶段的前后。正好和第一、第三个生命周期阶段对应。通过图能更好理解:
.png)
InstantiationAwareBeanPostProcessor
InstantiationAwareBeanPostProcessor实际上继承了BeanPostProcessor接口,严格意义上来看他们不是两兄弟,而是两父子。但是从生命周期角度我们重点关注其特有的对实例化阶段的影响,图中省略了从BeanPostProcessor继承的方法。
在MyInstitationProcessor的postProcessBeforeInstantiation方法上打上断点,通过调试,可以清晰地看到该方法的调用路径。

可以看到,postProcessBeforeInstantiation在doCreateBean之前调用,也就是在bean实例化之前调用的,英文源码注释解释道该方法的返回值会替换原本的Bean作为代理,这也是Aop等功能实现的关键点。

可以看到该方法在属性赋值方法内,但是在真正执行赋值操作之前。其返回值为boolean,返回false时可以阻断属性赋值阶段(continueWithPropertyPopulation = false;)。
BeanPostProcessor
关于BeanPostProcessor执行阶段的源码穿插在下文Aware接口的调用时机分析中,因为部分Aware功能的就是通过他实现的!只需要先记住BeanPostProcessor在初始化前后调用就可以了。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// ...
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
invokeInitMethods(beanName, wrappedBean, mbd);
}
//...
return wrappedBean;
}
|
这一大类接口的特点是功能丰富,常用于用户自定义扩展。
第二大类中又可以分为两类:
Aware类型的接口
生命周期接口,无所不知的Aware。Aware类型的接口的作用就是让我们能够拿到Spring容器中的一些资源。基本都能够见名知意,Aware之前的名字就是可以拿到什么资源,例如BeanNameAware可以拿到BeanName,以此类推。调用时机需要注意:所有的Aware方法都是在初始化阶段之前调用的!
Aware接口众多,这里同样通过分类的方式帮助大家记忆。Aware接口具体可以分为两组,至于为什么这么分,详见下面的源码分析。如下排列顺序同样也是Aware接口的执行顺序,能够见名知意的接口不再解释。
Aware Group1
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
Aware Group2
- EnvironmentAware
- EmbeddedValueResolverAware: 这个知道的人可能不多,实现该接口能够获取Spring EL解析器,用户的自定义注解需要支持spel表达式的时候可以使用,非常方便。
- ApplicationContextAware: ( ResourceLoaderAware \ ApplicationEvent PublisherAware \ MessageSourceAware) 这几个接口可能让人有点懵,实际上这几个接口可以一起记,其返回值实质上都是当前的ApplicationContext对象,因为ApplicationContext是一个复合接口。
Aware调用时机源码分析
详情如下,忽略了部分无关代码。代码位置就是我们上文提到的initializeBean方法详情,这也说明了Aware都是在初始化阶段之前调用的!
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
|
// Aware相关的接口都是在initializeBean方法中调用,但调用时机不太相同
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
// 这段代码invokeAwareMethods调用Group1中BeanXXXAware
if (System.getSecurityManager() != null) {
AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
invokeAwareMethods(beanName, bean);
return null;
}, getAccessControlContext());
} else {
invokeAwareMethods(beanName, bean);
}
// 这里调用Group2中的几个Aware,调用postProcessBeforeInitialization
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
// 调用初始化方法
try {
invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable ex) {
// ...
}
// 调用postProcessAfterInitialization
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
|
可以看到并不是所有的Aware接口都使用同样的方式调用。Bean××Aware都是在代码中直接调用的,而ApplicationContext相关的Aware都是通过BeanPostProcessor#postProcessBeforeInitialization()实现的。感兴趣的可以自己看一下ApplicationContextAwareProcessor这个类的源码,就是判断当前创建的Bean是否实现了相关的Aware方法,如果实现了会调用回调方法将资源传递给Bean。
至于Spring为什么这么实现,应该没什么特殊的考量。也许和Spring的版本升级有关。基于对修改关闭,对扩展开放的原则,Spring对一些新的Aware采用了扩展的方式添加。
BeanPostProcessor的调用时机也能在这里体现,包围住invokeInitMethods方法,也就说明了在初始化阶段的前后执行。关于Aware接口的执行顺序,其实只需要记住第一组在第二组执行之前就行了。每组中各个Aware方法的调用顺序其实没有必要记,有需要的时候点进源码一看便知。
生命周期接口
至于剩下的两个生命周期接口就很简单了,实例化和属性赋值都是Spring帮助我们做的,能够自己实现的有初始化和销毁两个生命周期阶段。
InitializingBean接口
InitializingBean顾名思义,是初始化Bean相关的接口。接口定义:
1
2
3
|
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
|
看方法名,是在读完Properties文件,之后执行的方法。afterPropertiesSet()方法是在初始化过程中被调用的。InitializingBean 对应生命周期的初始化阶段,在上面源码的invokeInitMethods(beanName, wrappedBean, mbd); 方法中调用。
有一点需要注意,因为Aware方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用Aware接口获取的资源,这也是我们自定义扩展Spring的常用方式。
除了实现InitializingBean接口之外还能通过注解(@PostConstruct)或者xml配置的方式指定初始化方法(init-method),至于这几种定义方式的调用顺序其实没有必要记。因为这几个方法对应的都是同一个生命周期,只是实现方式不同,我们一般只采用其中一种方式。
三种实现指定初始化方法的方法
- 使用@PostConstruct注解,该注解作用于void方法上
1
2
3
4
5
6
7
8
|
public class Person {
...
@PostConstruct
public void addTitle() {
this.title = "Mr. ";
}
...
}
|
- 在配置文件中配置init-method方法
1
2
3
|
<bean id="person" class="net.liwenbo.myspring.Person" init-method="addTitle">
...
</bean>
|
- 将类实现InitializingBean接口
1
2
3
4
5
6
7
8
|
public class Person implements InitializingBean {
...
@Override
public void afterPropertiesSet() throws Exception {
this.title = "Mr. ";
}
}
|
DisposableBean接口
DisposableBean类似于InitializingBean,对应生命周期的销毁阶段,以ConfigurableApplicationContext#close()方法作为入口,实现是通过循环获取所有实现了DisposableBean接口的Bean然后调用其destroy()方法 。
接口定义:
1
2
3
4
5
6
7
8
|
public interface DisposableBean {
/**
* Invoked by the containing {@code BeanFactory} on destruction of a bean.
* @throws Exception in case of shutdown errors. Exceptions will get logged
* but not rethrown to allow other beans to release their resources as well.
*/
void destroy() throws Exception;
}
|
定义一个实现了DisposableBean接口的Bean:
1
2
3
4
5
6
7
|
public class Person implements DisposableBean {
...
@Override
public void destroy() throws Exception {
System.out.println("destroy my bean!");
}
}
|
也就是说,在对象销毁的时候,会去调用DisposableBean的destroy方法。在进入到销毁过程时先去调用一下DisposableBean的destroy方法,然后后执行 destroy-method声明的方法(用来销毁Bean中的各项数据)。
BeanPostProcessor注册时机与执行顺序
首先要明确一个概念,在spring中一切皆bean。所有的组件都会被作为一个bean装配到spring容器中,过程如下图:

所以我们前面所讲的那些拓展点,也都会被作为一个个bean装配到spring容器中。
注册时机: 我们知道BeanPostProcessor也会注册为Bean,那么Spring是如何保证BeanPostProcessor 在我们的业务Bean之前初始化完成呢?
请看我们熟悉的refresh()方法的源码,可以看出,Spring是先执行registerBeanPostProcessors()进行BeanPostProcessors的注册,然后再执行finishBeanFactoryInitialization创建我们的单例非懒加载的Bean。
执行顺序:
BeanPostProcessor有很多个,而且每个BeanPostProcessor都影响多个Bean,其执行顺序至关重要,必须能够控制其执行顺序才行。关于执行顺序这里需要引入两个排序相关的接口:PriorityOrdered、Ordered
- PriorityOrdered是一等公民,首先被执行,PriorityOrdered公民之间通过接口返回值排序
- Ordered是二等公民,然后执行,Ordered公民之间通过接口返回值排序
- 都没有实现是三等公民,最后执行
在以下源码中,可以很清晰的看到Spring注册各种类型BeanPostProcessor的逻辑,根据实现不同排序接口进行分组。优先级高的先加入,优先级低的后加入。根据排序接口返回值排序,默认升序排序,返回值越低优先级越高。
FactoryBean 和 BeanFactory 区别
BeanFactory 是 Bean 的工厂, ApplicationContext 的父类,IOC 容器的核心,负责生产和管理 Bean 对象。
FactoryBean 是 Bean,可以通过实现 FactoryBean 接口定制实例化 Bean 的逻辑,通过代理一个Bean对象,对方法前后做一些操作。
- BeanFactory 是ioc容器的底层实现接口,是ApplicationContext 顶级接口。
Spring不允许我们直接操作 BeanFactory bean工厂,所以为我们提供了ApplicationContext 这个接口 此接口集成BeanFactory 接口,ApplicationContext包含BeanFactory的所有功能,同时还进行更多的扩展。
BeanFactory 接口又衍生出以下接口,其中我们经常用到的是ApplicationContext 接口。
- FactoryBean 是spirng提供的工厂bean的一个接口**。**
FactoryBean 接口提供三个方法,用来创建对象,FactoryBean 具体返回的对象是由getObject 方法决定的。
1
2
3
4
5
6
7
8
9
10
11
12
|
public interface FactoryBean<T> {
// 创建具体的Bean对象类型
@Nullable T getObject() throws Exception;
// 返回这个工厂Bean创建的对象的类型
@Nullable Class<?> getObjectType();
// 是否是单例,默认true
default boolean isSingleton() {
return true;
}
}
|
例如,下面的代码创建了一个FactoryBean 用来生产Person对象。
1
2
3
4
5
6
7
8
9
10
11
|
public class PersonFactoryBean implements FactoryBean<Person> {
@Override
public Person getObject() throws Exception {
return new Person();
}
@Override
public Class<?> getObjectType() {
return Person.class;
}
}
|
总之,BeanFactory是个bean 工厂,是一个工厂类(接口), 它负责生产和管理bean的一个工厂,是ioc 容器最底层的接口,是个ioc容器,是spring用来管理和装配普通bean的ioc容器(这些bean成为普通bean)。
FactoryBean是个bean,在IOC容器的基础上给Bean的实现加上了一个简单工厂模式和装饰模式,是一个可以生产对象和装饰对象的工厂bean,由spring管理后,生产的对象是由getObject()方法决定的(从容器中获取到的对象不是“ FactoryBeanTest ” 对象)。
Spring 如何解决循环依赖
Spring是如何处理循环依赖的,比如几个Bean之间的互相引用,例如下面的代码,PersonA依赖于PersonB,PersonB依赖于PersonC,PersonC依赖于PersonA。
1
2
3
4
5
6
7
8
9
10
11
|
@Component
public class PersonA {
@Autowired
private PersonB personB;
private String name;
public PersonA() {
name = "personA";
}
}
|
1
2
3
4
5
6
7
8
9
10
11
|
@Component
public class PersonB {
@Autowired
private PersonC personC;
private String name;
public PersonB() {
name = "PersonB";
}
}
|
1
2
3
4
5
6
7
8
9
10
11
|
@Component
public class PersonC {
@Autowired
private PersonC personC;
private String name;
public PersonC() {
name = "PersonC";
}
}
|
如果三个类都不是单例的方式 ,那么Spring肯定会报循环依赖的异常。对于循环依赖链上有单例的情况,Spring主要是采用三级缓存的方式来解决循环依赖。
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
|
// DefaultSingletonBeanRegistry.java
// Spring解决循环依赖的关键在于这个类
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
/** Cache of singleton objects: bean name to bean instance. */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
/** Cache of singleton factories: bean name to ObjectFactory. */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
/** Cache of early singleton objects: bean name to bean instance. */
private final Map<String, Object> earlySingletonObjects = new ConcurrentHashMap<>(16);
/** Set of registered singletons, containing the bean names in registration order. */
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
/**
* Add the given singleton factory for building the specified singleton
* if necessary.
* <p>To be called for eager registration of singletons, e.g. to be able to
* resolve circular references.
* @param beanName the name of the bean
* @param singletonFactory the factory for the singleton object */
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
Assert.notNull(singletonFactory, "Singleton factory must not be null");
synchronized (this.singletonObjects) {
if (!this.singletonObjects.containsKey(beanName)) {
this.singletonFactories.put(beanName, singletonFactory);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
}
|
具体的解决循环依赖的细节,可以通过调试Bean创建的过程梳理清楚。Spring 解决循环依赖的方法可以总结为下面几点:
1. 首先, Spring 提供 setAllowCircularReferences 方法可以设置是否开启循环依赖,默认是允许循环依赖。
2. 其次, Spring 设计了三个集合来处理循环依赖,分别是 singletonFactories,earlySingletonObjects,registeredSingletons
-
singletonFactories 用来缓存 Bean 创建的 Lamdba 表达式创建方法;
-
earlySingletonObjects 用来缓存早期的 bean 的引用;
-
registeredSingletons 记录已经注册的 bean。
3. 最后, 当一个类 A 通过字段注入的方式依赖另一个类 B 的时候,如果 IoC 容器也没有 B 类的缓存,核心方法 DefaultSingletonBeanRegistry#getSingleton(java.lang.String, boolean)
- 先从 singletonFactories 获取到当前 bean 的实例创建方法;
- 再通过 getObject 方法获取到早期的 bean 的实例引用;
- 最后将这个 bean 的实例设置当前的字段属性中。
Sring核心源码总结
Spring Bean的生命周期分为四个阶段 和 多个扩展点。扩展点又可以分为 影响多个Bean 和 影响单个Bean。整理如下:
四个阶段
- 实例化 Instantiation
- 属性赋值 Populate
- 初始化 Initialization
- 销毁 Destruction
多个扩展点
影响多个Bean
- BeanPostProcessor
- InstantiationAwareBeanPostProcessor
影响单个Bean
-
Aware
- Aware Group1
- BeanNameAware
- BeanClassLoaderAware
- BeanFactoryAware
- Aware Group2
- EnvironmentAware
- EmbeddedValueResolverAware
- ApplicationContextAware( ResourceLoaderAware \ ApplicationEventPublisherAware \ MessageSourceAware)
-
生命周期
- InitializingBean
- DisposableBean