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
16
17
18
19
20
21
22
23
24
25
26
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建XmlBeanDefinitionReader并交给BeanFactory
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

// 为beanDefinitionReader配置资源加载环境
beanDefinitionReader.setEnvironment(getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

// 配置beanDefinitionReader内部的验证方式, 用于校验xml文件合法性(XSD/DTD)
initBeanDefinitionReader(beanDefinitionReader);
// 解析xml文件, 生成并注册BeanDefinition
loadBeanDefinitions(beanDefinitionReader);
}

// 生成并注册BeanDefinition方法实现
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations = getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}

加载BeanDefinition时, 先通过AbstractBeanDefinitionReaderloadBeanDefinitions方法读取配置文件, 将其转换成Resource资源对象. 接着使用XmlBeanDefinitionReaderdoLoadBeanDefinitions方法解析xml, 生成对应的Document对象. 然后遍历Document对象中的Element, 委托给BeanDefinitionParserDelegate解析, 主要包括:

  1. 读取id/name/alias
  2. 校验name/alias的唯一性
  3. 读取class/parent属性
  4. 调用BeanDefinitionReaderUtils.createBeanDefinition生成GenericBeanDefinition实例
  5. 解析并设置singleton/lazy-init/autowire/depends-on/primary/init-method/destroy-method/Factory-bean/factory-method等属性值
  6. 解析并设置构造函数参数配置
  7. 解析并设置实例属性(property)设置
  8. 创建并返回BeanDefinitionHolder, 将刚刚创建的BeanDefinition进行包装(BeanDefinition+beanName+aliases)

最后使用BeanDefinitionReaderUtils调用DefaultListableBeanFactoryregisterBeanDefinition方法, 使用beanNamealiasBeanDefinition进行注册

prepareBeanFacotry(beanFactory)

  • 配置classloader

  • 配置SPEL表达式解析器(#{...})StandardBeanExpressionResolver

  • 配置一个属性编辑器ResourceEditorRegistrar, 该类实现PropertyEditor, 此为java标准, 主要服务GUI, 实现String与Object互转.与之搭配的有TypeConverter接口进行统一封装, 3.0之后可能交由ConversionService处理

    从spring3.0开始, SPring重新设计了一套类型转换接口, 核心接口有: Converter ConverterFactoryGenericConverter. 在此基础上定义了ConversionService整合他们三个, 统一话接口操作, 可以称其为门面接口. 除此之外还有Formatter<T>接口能将Object转换成类型T也可以实现类型转换, 但它主要侧重与格式化, 一般用于时间/日期, 数字, 货币等场景.

  • 添加ApplicationContextAware接口后置处理器

  • 配置几个忽略自动装配的Aware接口(EnvironmentAware ResourceLoaderAware ApplicationEventPublisherAware MessageSourceAware ApplicationContextAware)

  • 配置几个自动装配的特殊类(BeanFactory ResourceLoader ApplicationEventPublisher ApplicationContext)

  • 配置一个Bean后置处理器, 用来检测实现了ApplicationListener接口的类

  • 注册单例(Environment systemProperties systemEnvironment)

postProcessBeanFactory(ConfigurableListableBeanFactory)

该方法在AbstractApplicationContext中是空方法, 子类中AbstractRefreshableWebApplicationContext重写该方法:

  • 添加了ServletContextAwareProcessor
  • 配置忽略自动注入接口ServletContextAware/ServletConfigAware
  • 注册单例对象servletContext
  • 注册环境对象属性servletContextservletConfig

invokeBeanFactoryPostProcessors(ConfigurableListableBeanFactory)

调用BeanFactoryPostProcessor

暂时为空

registerBeanPostProcessors(ConfigurableListableBeanFactory)

BeanFactory中获取BeanPostProcessor列表并调用

暂时为空

initMessageSource

消息提示内容国际化

initApplicationEventMulticaster

初始化应用事件广播器SimpleApplicationEventMulticaster, 并作为单例注册到BeanFactory

onRefresh

空, 留个容器子类扩展

registerListeners

注册ApplicationListener实例

finishBeanFactoryInitialization(ConfigurableListableBeanFactory)

实例化剩余单例对象

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