spring-refresh方法分析

spring源码版本: 4.3.1-RELEASE

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
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 设置启动时间和启动标识active为true
// 如果是web应用, 则会替换servletContextInitParams和servletConfigInitParams配置
prepareRefresh();

// 创建DefaultListableBeanFactory, 加载BeanDefinition
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// 设置BeanClassLoader, PropertyEditor注册器, 一些AwareProcessor
// 把一些Aware接口排除出autowire
prepareBeanFactory(beanFactory);

try {
// 给子类处理BeanFactory的机会, web容器时会增加一个BeanPostProcessor和排除一些Aware接口
postProcessBeanFactory(beanFactory);

// 初始化并且执行已经注册的BeanFactoryPostProcessor
invokeBeanFactoryPostProcessors(beanFactory);

// 初始化并执行已经注册的BeanPostProcessor
registerBeanPostProcessors(beanFactory);

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

// 初始化容器事件广播器
initApplicationEventMulticaster();

// 给子类参与refresh的机会, web容器会在这里初始化主题资源
onRefresh();

// 注册容器事件监听器
registerListeners();

// 初始化剩余的非懒加载的单例bean, 开发人员定义的bean基本上是在这里实例化的
finishBeanFactoryInitialization(beanFactory);

// 初始化LifecycleProcessor, 发布容器刷新事件
finishRefresh();
}

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

// 销毁所有已经创建的单例
destroyBeans();

// 重置active标识
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}

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

prepareRefresh()

主要是设置当前ApplicationContext的启动时间, activeclosed标志位; 执行留给子类的扩展方法initPropertySources(); 验证系统必填属性(Spring默认没有配置必填属性)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);

if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}

// 留给子类初始化属性资源
initPropertySources();

// 验证必填属性
getEnvironment().validateRequiredProperties();

// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}
  • initPropertySources()AbstractApplicationContext中实现是空的, 这是留给子类覆盖的, 这样就给了用户扩展的能力. 在web应用中, 子类AbstractRefreshableWebApplicationContext就利用覆盖整个方法将Servlet属性ServletContextservletConfig注册到了系统属性资源中.

  • getEnvironment().validateRequiredProperties()的实现是在AbstractEnvironment中, 整个方法用来验证一些必填属性, 而Spring默认是没有设置必填属性的, 所以这个方法的意义是什么呢? 扩展性! 如果我们自己有校验必填属性的需求, 比如我们要求应用启动时必须设置日志目录参数logDir, 就可以创建自己的ApplicationContext, 继承XmlWebApplication, 然后通过重写initPropertySources()方法设置该属性必填.

    1
    2
    3
    4
    5
    6
    7
    public class MyApplicationContext extends XmlWebApplicationContext {
    @Override
    protected void initPropertySources() {
    super.initPropertySources();
    getEnvironment().setRequiredProperties("logDir");
    }
    }

    当我们运行项目时可以通过JVM参数-DlogDir=/tmp/log传递属性值, 如果不传递应用就会抛出MissingRequiredPropertiesException异常. 当然我们需要在web.xml中通过如下配置指定使用我们的自定义的MyApplicationContext.

    1
    2
    3
    4
    <context-param>
    <param-name>contextClass</param-name>
    <param-value>com.tonny.study.MyApplicationContext</param-value>
    </context-param>

obtainFreshBeanFactory()

初始化BeanFactory, 加载BeanDefinition

1
2
3
4
5
6
7
8
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = getBeanFactory();
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}

核心方法在refreshBeanFactory(), 它完成了创建BeanFactory和加载BeanDefinition

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// AbstractRefreshableApplicationContext#refreshBeanFactory
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory);
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

  1. 如果当前容器已经存在一个BeanFactory, 则将其销毁
  2. 通过createBeanFactory()创建一个BeanFactory实例, 具体创建的是DefaultListableBeanFactory
  3. 自定义BeanFactory, spring的默认实现做了两件事: 是否允许覆盖同名称的不同定义的对象; 是否允许bean之间存在循环依赖.
  4. 加载BeanDefinition
  5. 将BeanFactory赋值给当前ApplicationContext

简单说下第3步, 先看方法实现

1
2
3
4
5
6
7
8
9
10
11
12
protected void customizeBeanFactory(DefaultListableBeanFactory beanFactory) {
// 如果属性allowBeanDefinitionOverriding不为空,设置给beanFactory对象相应属性
// 此属性的含义:是否允许覆盖同名称的不同定义的对象
if (this.allowBeanDefinitionOverriding != null) {
beanFactory.setAllowBeanDefinitionOverriding(this.allowBeanDefinitionOverriding);
}
// 如果属性allowCircularReferences不为空,设置给beanFactory对象相应属性
// 此属性的含义:是否允许bean之间存在循环依赖
if (this.allowCircularReferences != null) {
beanFactory.setAllowCircularReferences(this.allowCircularReferences);
}
}

Spring默认是没有对这两个属性进行设置的, 所以其实两个if判断都没有进, 那这两个属性有什么意义呢? 还是那句话, 扩展性, 子类可以通过覆盖customizeBeanFactory()修改这两个属性的配置.

下面重点说下第5步, 先看实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建XmlBeanDefinitionReader并交给BeanFactory
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

// Allow a subclass to provide custom initialization of the reader,
// then proceed with actually loading the bean definitions.
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}

参考资料:
【死磕 Spring】—– 深入分析 ApplicationContext 的 refresh()
Spring源码分析(二十)准备环境
Spring源码分析(二十一)加载BeanFactory