引言

经过前一阵子的学习,了解了从BeanFactory角度加载bean的流程,但是一般使用spring都是使用ApplicationContent来加载配置文件,获取bean。
ApplicationContent在实现BeanFactory接口的前提下,还有很多其他的功能,比如国际化、资源加载等。
下面从一段代码开始本系列:

1
2
3
4
//上下文
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//获取bean
Object beanV1 = ac.getBean("xxx");

以前分析BeanFactory的代码:

1
2
3
4
5
6
7
8
//资源定位
ClassPathResource resource = new ClassPathResource("bean.xml");
//bean工厂
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//xml BeanDefinition 阅读器
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
//加载与注册BeanDefinition,完成后的BeanDefinition放置在IOC容器中。
reader.loadBeanDefinitions(resource);

首先贴一张ClassPathXmlApplicationContext继承体系图:
ClassPathXmlApplicationContext.png

1、ClassPathXmlApplicationContext的构造函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* 使用给定的父类创建一个新的ClassPathXmlApplicationContext,
* 从给定的XML文件中加载定义。
*
* @param configLocations 资源位置数组
* @param refresh 是否自动刷新上下文、加载所有bean定义并创建所有单例。
* 或者,在进一步配置上下文之后手动调用refresh
* @param parent 父上下文
* @throws BeansException 如果上下文创建失败
* @see #refresh()
*/
public ClassPathXmlApplicationContext(
String[] configLocations, boolean refresh, @Nullable ApplicationContext parent)
throws BeansException {
//设置父上下文,环境之类
super(parent);
//设置此应用程序上下文的配置位置。
setConfigLocations(configLocations);
//刷新上下文
if (refresh) {
refresh();
}
}

可以看出refresh()是一个很重要的方法,加载或刷新配置。
配置可以是XML文件、属性文件或关系数据库模式。由于这是一种启动方法,如果失败,它应该销毁已经创建的单例,以避免挂起资源。换句话说,在调用该方法之后,应该实例化所有或根本不实例化单例。其定义在ConfigurableApplicationContext接口中,默认实现在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
52
53
54
55
56
57
58
59
60
61
62
@Override
public void refresh() throws BeansException, IllegalStateException {
//"refresh" and "destroy"的同步锁
synchronized (this.startupShutdownMonitor) {
// 准备好刷新上下文。
prepareRefresh();

// 告诉子类刷新内部bean工厂。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// 准备bean工厂,以便在此上下文中使用。
prepareBeanFactory(beanFactory);

try {
// 允许在上下文子类中对bean工厂进行后处理。
postProcessBeanFactory(beanFactory);

// 调用上下文中注册为bean的工厂处理器。
invokeBeanFactoryPostProcessors(beanFactory);

// 注册拦截bean创建的bean处理器。
registerBeanPostProcessors(beanFactory);

// 初始化此上下文的消息源。
initMessageSource();

// 初始化此上下文的事件多播程序。
initApplicationEventMulticaster();

// 在特定上下文子类中初始化其他特殊bean。
onRefresh();

// 检查侦听器bean并注册它们。
registerListeners();

// 实例化所有剩余的(非惰性初始化)单例。
finishBeanFactoryInitialization(beanFactory);

// 最后一步:发布相应的事件。
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}

// 销毁已经创建的单例,以避免挂起资源。
destroyBeans();

// Reset 'active' flag.
cancelRefresh(ex);

// 将异常传播给调用者。
throw ex;
} finally {
// 重置Spring核心中的公共内省缓存,
// 因为我们可能再也不需要单例bean的元数据了……
resetCommonCaches();
}
}
}

很长的流程,下面慢慢分析。

prepareRefresh()

准备此上下文用于刷新、设置其启动日期和活动标志以及执行任何属性源的初始化。
这个方法比较简单:

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
/**
* 准备此上下文用于刷新、设置其启动日期和活动标志以及执行任何属性源的初始化。
*/
protected void prepareRefresh() {
// Switch to active.
this.startupDate = System.currentTimeMillis();
this.closed.set(false);
this.active.set(true);

if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
} else {
logger.debug("Refreshing " + getDisplayName());
}
}

// 在上下文环境中初始化任何占位符属性源。
initPropertySources();

// 验证所有标记为需要的属性都是可解析的:
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();

// Store pre-refresh ApplicationListeners...
if (this.earlyApplicationListeners == null) {
this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
} else {
// Reset local application listeners to pre-refresh state.
this.applicationListeners.clear();
this.applicationListeners.addAll(this.earlyApplicationListeners);
}

// 允许收集早期的ApplicationEvents,一旦多播可用,就可以发布它们……
this.earlyApplicationEvents = new LinkedHashSet<>();
}

1.1、ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

获取beanFactory,分析这个方法的时候要参考ClassPathXmlApplicationContext继承图,而且还会遇到熟悉的地方:

1
2
3
4
5
6
7
//告诉子类刷新内部bean工厂。
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//刷新bean工厂,这里使用了子类AbstractRefreshableApplicationContext中的实现
refreshBeanFactory();
//获取bean工厂
return getBeanFactory();
}

分为两步:

  1. 刷新BeanFactory
  2. 获取BeanFactory

都是在子类AbstractRefreshableApplicationContext中的实现:
此实现对该上下文的底层bean工厂执行实际刷新,如果有的话关闭前一个bean工厂,并为上下文生命周期的下一阶段初始化一个新的bean工厂。

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
@Override
protected final void refreshBeanFactory() throws BeansException {
//如果已经持有一个BeanFactory
if (hasBeanFactory()) {
//用于销毁此上下文管理的所有bean
destroyBeans();
//关闭持有的BeanFactory
closeBeanFactory();
}
try {
//新建一个 DefaultListableBeanFactory
DefaultListableBeanFactory beanFactory = createBeanFactory();
beanFactory.setSerializationId(getId());
// 自定义此上下文使用的内部bean工厂。
// allowBeanDefinitionOverriding
// allowCircularReferences
customizeBeanFactory(beanFactory);
//加载BeanDefinitions
loadBeanDefinitions(beanFactory);
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}

其中loadBeanDefinitions(beanFactory)方法在AbstractXmlApplicationContext中实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//通过XmlBeanDefinitionReader加载bean定义。
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// Create a new XmlBeanDefinitionReader for the given BeanFactory.
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

// Configure the bean definition reader with this context's
// resource loading environment.
beanDefinitionReader.setEnvironment(this.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);
}

发现和以前分析BeanFactory时写的例子很像:

1
2
3
4
5
6
7
8
//资源定位
ClassPathResource resource = new ClassPathResource("bean.xml");
//bean工厂
DefaultListableBeanFactory factory = new DefaultListableBeanFactory();
//xml BeanDefinition 阅读器
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);
//加载与注册BeanDefinition,完成后的BeanDefinition放置在IOC容器中。
reader.loadBeanDefinitions(resource);

再之后就不分析了,可以参考以前分析文章,最终将解析好的BeanDifinition放到DefaultListableBeanFactory中。

1.2、prepareBeanFactory(beanFactory)

配置工厂的标准上下文特征,例如上下文的类加载器和后处理程序。

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
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 调用内部bean工厂来使用上下文的类加载器等。
beanFactory.setBeanClassLoader(getClassLoader());
beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

// 使用上下文回调配置bean工厂。.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

//在普通工厂中未注册为可解析类型的BeanFactory接口。
//MessageSource注册(并为自动装配找到)为bean。
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);

// 将早期后处理器注册为application监听器,用于检测内部bean。
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

// 检测LoadTimeWeaver并准备编织(如果找到)。
if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
// 为类型匹配设置一个临时类加载器。
beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
}

// 注册缺省环境bean。
if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
}
if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
}
if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
}
}

tencent.jpg