Spring 使用简单Demo进行源码调试(二)

版权声明:本文为博主原创文章,转载请注明出处,谢谢!

版权声明:本文为博主原创文章,转载请注明出处:http://blog.jerkybible.com/2015/05/09/Spring 使用简单Demo进行源码调试(二)/

访问原文「Spring 使用简单Demo进行源码调试(二)

接上一篇文章 Spring 使用简单Demo进行源码调试(一)

在运行到下面语句

1
ApplicationContext ctx = new ClassPathXmlApplicationContext("bean.xml");// 读取bean.xml中的内容

该构造函数首先进入下面ClassPathXmlApplicationContext类中这段代码。代码中configLocations为我们的配置文件,及[bean.xml];refresh表示是否刷新,这里为true,表示刷新配置;parent表示上级上下文,这里为null表示没有上级上下文。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* 使用上一级上下文创建新的ClassPathXmlApplicationContext,
* 从XML中加载定义
* @param configLocations 资源地址列表
* @param refresh 是否刷新上下文,
* @param parent 上一级上下文
*/
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {
//parent = null;
//refresh= true;
//configLocations=[bean.xml];
super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}

下面是抽象函数AbstractRefreshableConfigApplicationContext中setConfigLocations方法。该方法为设置配置文件,及将[bean.xml]设置为本地的this.configLocations属性。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 为应用的上下文设置配置地址.
* 如果没有设置,会使用默认的配置
*/
public void setConfigLocations(String[] locations) {
if (locations != null) {
Assert.noNullElements(locations, "Config locations must not be null");
this.configLocations = new String[locations.length];
for (int i = 0; i < locations.length; i++) {
this.configLocations[i] = resolvePath(locations[i]).trim();
}
}
else {
this.configLocations = null;
}
}

接着是refresh函数,该函数在AbstractApplicationContext类中,代码如下。可以看到该函数一共分为以下几步:
1. 为了刷新准备上下文;
2. 利用子类完成内部bean factory的刷新;
3. 使用本地上下文准备bean factory;
4. 允许在上下文子类中完成bean factory后处理;
5. 调用上下文注册的bean factory处理器;
6. 注册拦截bean创建的bean处理器;
7. 初始化上下文中消息源;
8. 初始化上下文中的事件多播;
9. 在特定上下文子类中初始化其他特殊bean;
10. 检查监听器bean并注册;
11. 实例化所有剩余(non-lazy-init)单例;
12. 发布相应的事件。

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
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// 为了刷新准备上下文
prepareRefresh();
// 利用子类完成内部bean factory的刷新
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 使用本地上下文准备bean factory
prepareBeanFactory(beanFactory);
try {
// 允许在上下文子类中完成bean factory后处理
postProcessBeanFactory(beanFactory);
// 调用上下文注册的bean factory处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截bean创建的bean处理器
registerBeanPostProcessors(beanFactory);
// 初始化上下文中消息源
initMessageSource();
// 初始化上下文中的事件多播
initApplicationEventMulticaster();
// 在特定上下文子类中初始化其他特殊bean
onRefresh();
// 检查监听器bean并注册
registerListeners();
// 实例化所有剩余(non-lazy-init)单例
finishBeanFactoryInitialization(beanFactory);
// 发布相应的事件
finishRefresh();
}
catch (BeansException ex) {
logger.warn("Exception encountered during context initialization - cancelling refresh attempt", ex);
// Destroy already created singletons to avoid dangling resources.
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}

这里的每一步可能都很繁琐,鉴于我也是第一次看这些代码,还是慢慢进行分析吧,先到这里。