前言

ApplicationContext实现了除基本容器外的多个接口,提供了比BeanFactory更为丰富的功能,比如说自动识别BeanPostProcessor以及其它特殊类型Bean、容器启动时自动加载Bean、国际化支持、容器内事件发布等。因此,我们在实际应用中一般会使用ApplicationContext而不是BeanFactory

继承体系

从上图可以看出,ApplicationContext继承了BeanFactory,因此拥有BeanFactory的全部功能,实际上,它是将容器的功能委派给DefaultListableBeanFactory来实现。除此之外,ApplicationContext还继承了ResourceLoaderEnvironmentCableApplicationEventPublisherMessageSource等接口,提供了十分丰富的功能。

源码分析

创建一个常用的ApplicationContext

1
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:application.xml");

ClassPathXmlApplicationContext的构造函数在设置完配置文件的位置后,紧接着调用refresh()方法,这个方法是整个ApplicationContext体系的核心,是在AbstractApplicationContext中实现的,并且是个典型的模板方法,也就是说其中的一些步骤是交由具体子类来实现的。以下是这个方法的代码:

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
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 1. 准备刷新时的上下文环境
prepareRefresh();

// 2. 刷新并初始化 BeanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// 3. 配置 BeanFactory 中的一些其它信息
prepareBeanFactory(beanFactory);

try {
// 4. 提供子类覆盖的额外处理,即子类处理自定义的 BeanFactoryPostProcess
postProcessBeanFactory(beanFactory);

// 5. 调用各种 BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);

// 6. 注册 BeanPostProcessor 到 BeanFactory 中去
registerBeanPostProcessors(beanFactory);

// 7. 初始化上下文中的资源文件,如国际化文件的处理等
initMessageSource();

// 8. 初始化上下文事件广播器
initApplicationEventMulticaster();

// 9. 初始化其它特殊 Bean
onRefresh();

// 10. 检查 listener 类型的 Bean 并注册
registerListeners();

// 11. 实例化所有非懒加载的单例 Bean
finishBeanFactoryInitialization(beanFactory);

// 12. 发布相应的事件
finishRefresh();
}

catch (BeansException ex) {
// ...
}

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

obtainFreshBeanFactory

obtainFreshBeanFactory()方法核心是内部调用refreshBeanFactory()方法并将容器内部的ConfigurableListableBeanFactory返回,从这也看到了ApplicationContextBeanFactory的关系:ApplicationContext内部包含一个BeanFactoryApplicationContext所有关于BeanFactory的功能将委派给此BeanFactory处理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protected final void refreshBeanFactory() throws BeansException {
// 清理之前的BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// createBeanFactory方法直接新建一个DefaultListableBeanFactory,也就是说内部使用的是DefaultListableBeanFactory实例
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 自定义此上下文使用的内部bean工厂
customizeBeanFactory(beanFactory);
// 将BeanDefinition加载到给定的bean工厂中,通常通过委托给一个或多个BeanDefinitionReader来实现
// 子类实现的方法,此处调用的是AbstractXmlApplicationContext的方法
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException(...);
}
}

也就是说这一步是构建ApplicationContext内部的BeanFactory,以及根据配置将BeanDefinition加载到BeanFactory中(此时并没有实例化Bean)。

prepareBeanFactory

配置内部BeanFactory的一些基础参数,比如ClassLoader等等。

postProcessBeanFactory

BeanFactory预处理,ClassPathXmlApplicationContext未重写,WebXmlApplicationContext有重写,这里不展开。

invokeBeanFactoryPostProcessors

在任何Bean的实例化之前,实例化并调用所有已注册的BeanFactoryPostProcessorBean,如果实现了PriorityOrdered或者Ordered接口则按顺序调用。此时允许BeanFactoryPostProcessor在实例化BeanDefinition之前对当前的配置数据进行修改。

registerBeanPostProcessors

将当前所有的BeanPostProcessor注册到BeanFactory中去,同样也是按照PriorityOrdered或者Ordered的顺序。这也是ApplicationContextBeanFactory的一个不同,BeanFactory必须自己手动的调用addBeanPostProcessor()方法。

initMessageSource

初始化MessageSource,如果没有定义则使用DelegatingMessageSource,实际是委派给父类的。

initApplicationEventMulticaster

初始化ApplicationEventMulticaster,如果没有定义则使用SimpleApplicationEventMulticaster

onRefresh

模板方法,交给子类来实现,一般是用于在实例化单例Bean之前调用特定Bean的初始化。

registerListeners

将所有ApplicationListener注册到ApplicationEventMulticaster中,然后将earlyApplicationEvents中定义的事件进行广播。

finishBeanFactoryInitialization

实例化所有剩余的非懒加载的单例Bean,就是遍历所有的beanName,然后挨个调用getBean(beanName)

finishRefresh

完成此上下文的刷新,调用LifecycleProcessoronRefresh()方法并发布ContextRefreshedEvent。主要是对于有生命周期的Bean,按照分组,调用其start()方法。

ApplicationContext使用

1
2
3
4
5
6
7
8
9
10
11
// beanFactory
UserService userService = context.getBean("userService", UserService.class);

// 事件
context.addApplicationListener(new WalkListener());
context.publishEvent(new WalkEvent(new User("Jerry")));
context.publishEvent(new WalkEvent(new User("Peter")));

// locale
context.getMessage("menu.edit", null, "Edit", Locale.US);
// ...

参考资料