IOC源码解析

通过查看源码,可以得到BeanFactory是Spring的顶级接口。
desc.png

它提供了一些getBean的方法,它的容器继承体系图,如下所示:

img.png

  通过其接⼝设计,可以看ApplicationContext除了继承BeanFactory的⼦接⼝,还继承了ResourceLoader(加载资源,用于读取文件等)MessageSource(国际化)等接⼝,因此其提供的功能也就更丰富了。

IOC容器初始化流程

准备工作

通过对示例代码进行断点,可以看到多个关键节点的发起位置,都是位于同一个方法:

img.png

进入此文件,找到对应的方法,可以看到里面有很多方法,对应了生命周期中的各个节点:

img_1.png

接下来需要去官网进行源码下载,然后导入idea,查看源码。

IOC容器初始化

常见的Spring启动方式分为两种:ClassPathApplicationContextAnnotationConfigApplicationContext
一种以配置文件方式启动,一种是以注解方式启动;

XML配置方式

ClassPathApplicationContext查看源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
// 调用父类初始化
super(parent);
// 设置本地的配置信息
setConfigLocations(configLocations);
// 完成Spring容器的初始化
if (refresh) {
refresh();
}
}

通过源码发现,最终是调用了AbstractApplicationContextrefresh方法。

AbstractApplicationContext

查看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
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
@Override
public void refresh() throws BeansException, IllegalStateException {
// 加锁,AbstractApplicationContext的close方法也会用到这个锁,为了:刷新时不让关闭
synchronized (this.startupShutdownMonitor) {
// 第⼀步:刷新前的预处理
// 设置Spring容器的启动时间、开始活跃状态、撤销关闭状态、验证环境变量里一些必须存在的属性等
prepareRefresh();

// 第⼆步:获取BeanFactory;默认实现是DefaultListableBeanFactory
// 加载BeanDefinition 并注册到 BeanDefinitionRegistry
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// 第三步:BeanFactory的预准备⼯作(BeanFactory进⾏⼀些设置,⽐如context的类加载器等)
prepareBeanFactory(beanFactory);

try {
// 第四步:BeanFactory准备⼯作完成后进⾏的后置处理⼯作
postProcessBeanFactory(beanFactory);

// 第五步:实例化实现了BeanFactoryPostProcessor接⼝的Bean,并完成调用
invokeBeanFactoryPostProcessors(beanFactory);

// 第六步:注册BeanPostProcessor(Bean的后置处理器),在创建bean的前后等执⾏
registerBeanPostProcessors(beanFactory);

// 第七步:初始化MessageSource组件(做国际化功能;消息绑定,消息解析);
initMessageSource();

// 第⼋步:初始化事件派发器
initApplicationEventMulticaster();

// 第九步:⼦类重写这个⽅法,在容器刷新的时候可以⾃定义逻辑
onRefresh();

// 第⼗步:注册应⽤的监听器。就是注册实现了ApplicationListener接⼝的监听器bean
registerListeners();

// 第⼗⼀步:初始化所有剩下的⾮懒加载的单例bean
// 初始化创建⾮懒加载⽅式的单例Bean实例(未设置属性)
// 填充属性
// 初始化⽅法调⽤(⽐如调⽤afterPropertiesSet⽅法、init-method⽅法)
// 调⽤BeanPostProcessor(后置处理器)对实例bean进⾏后置处
finishBeanFactoryInitialization(beanFactory);

// 第⼗⼆步:完成context的刷新。主要是调⽤LifecycleProcessor的onRefresh()⽅法,并且发布事件 (ContextRefreshedEvent)
finishRefresh();
}

catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +"cancelling refresh attempt: " + ex);
}

// 销毁已创建的 singletons 实例
destroyBeans();

// 重置 'active' 标志.
cancelRefresh(ex);

// 将异常传播给调用方
throw ex;
}

finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}

通过梳理发现,refresh方法中主要逻辑为:

  1. BeanFactory的初始化,以及加载BeanDefinition;
  2. BeanFactoryPostProcessor的处理;
  3. 注册BeanPostProcessor;
  4. 执行finishBeanFactoryInitialization方法;

BeanFactory创建流程

  通过断点,可以发现ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory(); 最终进入的是AbstractRefreshableApplicationContext类,源码如下:

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
protected final void refreshBeanFactory() throws BeansException {
// 判断是否已经有bean factory,内部有锁保证线程安全
if (this.hasBeanFactory()) {
// 销毁 beans
this.destroyBeans();
// 关闭 bean factory
this.closeBeanFactory();
}

try {
// 实例化 DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
// 设置序列化ID
beanFactory.setSerializationId(this.getId());
// 自定义工厂的属性,比如是否覆盖、是否允许循环依赖
this.customizeBeanFactory(beanFactory);
// 加载注册 BeanDefinitions
this.loadBeanDefinitions(beanFactory);
synchronized(this.beanFactoryMonitor) {
// 最终赋值
this.beanFactory = beanFactory;
}
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
}
}

时序图如下:

img.png

BeanDefinitions加载流程

  从上面可知,BeanDefinitions的加载流程是从this.loadBeanDefinitions(beanFactory);开始,然后进入了AbstractXmlApplicationContextloadBeanDefinitions方法,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 为beanFactory创建一个XmlBeanDefinitionReader读取器对象,用于读取解析xml
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 提供给子类实现,提供了一些自定义的初始化策略
this.initBeanDefinitionReader(beanDefinitionReader);
// 加载BeanDefinitions
this.loadBeanDefinitions(beanDefinitionReader);
}

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 从Resources资源中进行加载
Resource[] configResources = this.getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
// 从xml配置文件加载
String[] configLocations = this.getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}

时序图如下所示:

img.png

经过XML解析器解析,然后调用BeanDefinitionReaderUtils注册BeanDefinition,最终进入默认的DefaultListableBeanFactory工厂中,将BeanDefinition保存在map中

注解方式

AnnotationConfigApplicationContext查看源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 默认的无参构造,初始化解析和扫描器
public AnnotationConfigApplicationContext() {
this.reader = new AnnotatedBeanDefinitionReader(this);
this.scanner = new ClassPathBeanDefinitionScanner(this);
}
// 通过注解配置类
public AnnotationConfigApplicationContext(Class<?>... componentClasses) {
// 调用无参构造
this();
// 注册
register(componentClasses);
// 完成Spring容器的初始化
refresh();
}
// 直接传入要扫描的包路径
public AnnotationConfigApplicationContext(String... basePackages) {
// 调用无参构造
this();
// 扫描指定的包
scan(basePackages);
// 完成Spring容器的初始化
refresh();
}

  可以发现,注解模式是首先进行包扫描或者类注册,然后也是进入了AbstractApplicationContextrefresh方法。
  根据调用时传入参数不同,如果是传入包路径则使用默认无参构造中的scanner,如果是注解扫描配置类则使用无参构造的reader,完成BeanDefinition注册。

BeanDefinition加载流程

时序图如下:

img.png

BeanFactory创建流程

  注解模式也是进入AbstractApplicationContextrefresh方法,代码和XML配置调用的是一样的。但是BeanFactory创建是不一样的,注解模式使用的是GenericApplicationContext类,源码如下:

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
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {

private final DefaultListableBeanFactory beanFactory;

@Nullable
private ResourceLoader resourceLoader;

private boolean customClassLoader = false;

private final AtomicBoolean refreshed = new AtomicBoolean();

public GenericApplicationContext() {
this.beanFactory = new DefaultListableBeanFactory();
}

public GenericApplicationContext(DefaultListableBeanFactory beanFactory) {
Assert.notNull(beanFactory, "BeanFactory must not be null");
this.beanFactory = beanFactory;
}

......

@Override
protected final void refreshBeanFactory() throws IllegalStateException {
if (!this.refreshed.compareAndSet(false, true)) {
throw new IllegalStateException(
"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
}
this.beanFactory.setSerializationId(getId());
}

......
}

可以看到在构造方法中,已经赋值了DefaultListableBeanFactory,和XML配置模式使用的是一样的。

Bean创建流程

非懒加载

根据上面的源码解析,可知Bean创建流程的起点是AbstractApplicationContext#refresh()⽅法的finishBeanFactoryInitialization(beanFactory) 处:

img.png

进入这个方法中,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
......
// 此处省略
......
// Stop using the temporary ClassLoader for type matching.
beanFactory.setTempClassLoader(null);

// Allow for caching all bean definition metadata, not expecting further changes.
beanFactory.freezeConfiguration();

// Instantiate all remaining (non-lazy-init) singletons.
// 实例化所以非懒加载的单例Bean
beanFactory.preInstantiateSingletons();
}

可以看到调用了DefaultListableBeanFactory类的preInstantiateSingletons⽅法,部分源码如下,可以看到⼯⼚Bean或者普通Bean,最终都是通过getBean的⽅法获取实例:

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
@Override
public void preInstantiateSingletons() throws BeansException {
......
// Iterate over a copy to allow for init methods which in turn register new bean definitions.
// While this may not be part of the regular factory bootstrap, it does otherwise work fine.
List<String> beanNames = new ArrayList<>(this.beanDefinitionNames);

// Trigger initialization of all non-lazy singleton beans...
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
// 非抽象类、单例、非延迟的bean才会加载
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
// 是否是工厂Bean
if (isFactoryBean(beanName)) {
// 工厂Bean获取需要加特殊前缀 &
Object bean = getBean(FACTORY_BEAN_PREFIX + beanName);
if (bean instanceof FactoryBean) {
final FactoryBean<?> factory = (FactoryBean<?>) bean;
boolean isEagerInit;
if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
isEagerInit = AccessController.doPrivileged((PrivilegedAction<Boolean>)
((SmartFactoryBean<?>) factory)::isEagerInit,
getAccessControlContext());
}
else {
isEagerInit = (factory instanceof SmartFactoryBean &&
((SmartFactoryBean<?>) factory).isEagerInit());
}
if (isEagerInit) {
// 具体获取Bean实例
getBean(beanName);
}
}
}
else {
// 具体获取Bean实例
getBean(beanName);
}
}
}

......
}

时序图如下:
img.png

懒加载

懒加载:即初始化时不进行加载,只有在第一次执行getBean去获取Bean对象时,才会执行加载

  根据上面Bean加载流程的源码分析,它只加载了非抽象类、单例、非延迟的bean,所以可以看到在getBean()之前,懒加载的Bean返回的是null:

img.png

  当getBean()执行完之后,懒加载的Bean也就完成加载:

img.png

  通过查看源码,可以看到具体的流程如下:

  1. 当传入的是BeanName时,进入AbstractBeanFactory类中的getBean()方法,源码如下:

img.png

最终进入AbstractBeanFactory类中的doGetBean()方法,然后后续就和Bean加载流程一致,完成加载;

  1. 当传入的是BeanClass时,则会进入DefaultListableBeanFactory类的resolveBean()方法,源码如下:

img.png

返回之前,调用了resolveNameBean()方法,源码如下:

img.png