【挑战 Spring】—– Spring IOC 源码调试二

前言

昨晚做了个梦……,好!上篇Spring IOC 源码调试一的进度进行到ClassPathXmlApplicationContext类构造方法中的refresh()方法,那这一篇就开始进入到大名鼎鼎的refresh()方法。

项目结构

这是调试代码

调试代码

开始调试

1.执行ClassPathXmlApplicationContextrefresh()方法

其中会先判断if (refresh),这个参数默认是true,点进new ClassPathXmlApplicationContext(location)这个代码中的构造方法就可以看到。然后执行refresh()方法,但是该方法被封装到了父类 AbstractApplicationContext中。

1
2
3
4
5
6
7
8
9
public ClassPathXmlApplicationContext( String[] configLocations, boolean refresh, @Nullable
ApplicationContext parent)throws BeansException {
super(parent);
setConfigLocations(configLocations);
if (refresh) {
// 调用父类 AbstractApplicationContext#refresh() 的方法
refresh();
}
}

2.执行AbstractApplicationContext类的refresh()方法

此时代码进到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
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// 创建并初始化 BeanFactory 容器(DefaultListableBeanFactory对象),后面很多方法都需要这个参数
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 填充 BeanFactory 功能
// 比如 context的 ClassLoader 和 后置处理器等等。
prepareBeanFactory(beanFactory);
try {
// 提供子类覆盖的额外处理,即子类处理自定义的BeanFactoryPostProcess
postProcessBeanFactory(beanFactory);
// 激活各种BeanFactory处理器
invokeBeanFactoryPostProcessors(beanFactory);
// 注册拦截Bean创建的Bean处理器,即注册 BeanPostProcessor
registerBeanPostProcessors(beanFactory);
// 初始化上下文中的资源文件,如国际化文件的处理等
initMessageSource();
// 初始化上下文事件广播器
initApplicationEventMulticaster();
//预留给 AbstractApplicationContext 的子类用于初始化其他特殊的 bean,该方法需要在所有单例 bean 初始化之前调用。
onRefresh();
// Check for listener beans and register them.
registerListeners();
// 初始化剩下的单例Bean(非延迟加载的)
finishBeanFactoryInitialization(beanFactory);
// Last step: publish corresponding event.
finishRefresh();
} catch (BeansException ex) {
if (logger.isWarnEnabled()) {
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;
} finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}
2-1.执行AbstractApplicationContext类的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
protected void prepareRefresh() {
// Switch to active.
// 设置启动日期
this.startupDate = System.currentTimeMillis();
// 设置 context 是否关闭的 状态
this.closed.set(false);
// 设置当前容器激活状态
this.active.set(true);
if (logger.isDebugEnabled()) {
if (logger.isTraceEnabled()) {
logger.trace("Refreshing " + this);
} else {
logger.debug("Refreshing " + getDisplayName());
}
}
// Initialize any placeholder property sources in the context environment.
//初始化context environment(上下文环境)中的占位符属性来源(该方法由子类去实现)
initPropertySources();
// Validate that all properties marked as required are resolvable:
// see ConfigurablePropertyResolver#setRequiredProperties
// 对 容器上下文环境 中的属性进行必要的验证
getEnvironment().validateRequiredProperties();
// 实例化一个 LinkedHashSet 存储 预刷新应用的监听器
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,一旦多主机可用就要发布
// todo 什么意思? 作用?
this.earlyApplicationEvents = new LinkedHashSet<>();
}
2-2.执行AbstractApplicationContext类的obtainFreshBeanFactory方法

obtainFreshBeanFactory方法中又调用了refreshBeanFactory()方法,但是在AbstractApplicationContext类中该方法是个空方法,并且此时调用refreshBeanFactory()方法的类依然是ClassPathApplicationContext对象,所以下一步进入到的ClassPathApplicationContext的父类AbstractRefreshableApplicationContextrefreshBeanFactory()方法中(多跟几遍代码,ClassPathApplicationContext类的继承关系就会理清楚了)

1
2
3
4
5
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
//初始化容器核心方法
refreshBeanFactory();
return getBeanFactory();
}
2-3. 执行AbstractRefreshableApplicationContextrefreshBeanFactory()方法

该方法中重要操作有:

  1. DefaultListableBeanFactory beanFactory = createBeanFactory()·:创建 BeanFactory 容器对象
  2. loadBeanDefinitions(beanFactory) :加载 BeanDefinition 们,具体提的类实现不同的方法
  3. this.beanFactory = beanFactory :将容器对象赋值给AbstractRefreshableApplicationContextprivate DefaultListableBeanFactory 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
/**
* 该方法是被final修饰 不允许被子类修改
* 该方法是 实例化容器 的重要方法
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
// 若已有 BeanFactory ,销毁它的 Bean 们,并销毁 BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建 BeanFactory 容器对象
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 设置 BeanFactory 的序列id
beanFactory.setSerializationId(getId());
// 定制 BeanFactory 设置相关属性
customizeBeanFactory(beanFactory);
// 加载 BeanDefinition 们,具体提的类实现不同的方法
loadBeanDefinitions(beanFactory);
// 加锁防止
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
2-4. (重点)执行AbstractRefreshableApplicationContextcreateBeanFactory()方法创建容器对象
2-4-1.执行DefaultListableBeanFactory(容器对象)的构造方法

其中new DefaultListableBeanFactory对象时,还调用了一个getInternalParentBeanFactory()方法。其中getInternalParentBeanFactory()方法封装在了AbstractRefreshableApplicationContext的父类AbstractApplicationContext

1
2
3
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}
2-4-2.getInternalParentBeanFactory()`方法

此时代码逻辑在AbstractApplicationContext类中。该方法是先获取容器应用上下文下文对象,如果有则传递给DefaultListableBeanFactory的构造方法。此时获取到的getParent()null,详情请见上篇博客的serParent(parent)部分

1
2
3
4
protected BeanFactory getInternalParentBeanFactory() {
return (getParent() instanceof ConfigurableApplicationContext ?
((ConfigurableApplicationContext) getParent()).getBeanFactory() : getParent());
}
2-4-3.实例化DefaultListableBeanFactory容器对象

此时进入DefaultListableBeanFactory构造方法,上一步中getInternalParentBeanFactory()方法获取到的返回值为null所以此时BeanFactory parentBeanFactory值为null。然后就是层层向上调用父类的构造方法。调用顺序:

DefaultListableBeanFactory–>AbstractAutowireCapableBeanFactory–>AbstractBeanFactory

其中执行AbstractAutowireCapableBeanFactory类构造方法时会有一些逻辑。

1
2
3
public DefaultListableBeanFactory(@Nullable BeanFactory parentBeanFactory) {
super(parentBeanFactory);
}
2-4-4.执行AbstractAutowireCapableBeanFactory类的有参构造方法

下面代码中看到在AbstractAutowireCapableBeanFactory构造方法中有两个操作

  1. this()调用了父类构造方法执行了三个ignoreDependencyInterface操作
  2. setParentBeanFactory(parentBeanFactory)此时parentBeanFactory参数为null。这个方法有些双亲委派的思想,而且这个方法具体实现是封装在了AbstractBeanFactory类中

AbstractAutowireCapableBeanFactory-有参构造方法.png

2-4-5. 简单说一下ignoreDependencyInterface方法

ignoreDependencyInterface 的主要功能是忽略给定接口的自动装配功能。

​ 啥意思?就是说你的类实现了被ignoreDependencyInterface()的接口,不能被自动注入到其他的Bean中。比如A类中有个B类的属性,但是B类实现了被ignoreDependencyInterface()的接口,此时你在A类中注入B,Spring时不会给你实例化B类的。

2-4-6. 完成DefaultListableBeanFactory(容器对象)实例化

此时从2-4-1到2-4-6就完成了DefaultListableBeanFactory对象的实例化,即完成了AbstractRefreshableApplicationContextcreateBeanFactory()方法—>回到AbstractRefreshableApplicationContextrefreshBeanFactory()方法中,下一步执行loadBeanDefinitions(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
类 :AbstractRefreshableApplicationContext
/**
* 该方法是被final修饰 不允许被子类修改
* 该方法是 实例化容器 的重要方法
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
// 若已有 BeanFactory ,销毁它的 Bean 们,并销毁 BeanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
//创建 BeanFactory 容器对象
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 设置 BeanFactory 的序列id
beanFactory.setSerializationId(getId());
// 定制 BeanFactory 设置相关属性
customizeBeanFactory(beanFactory);
// 加载 BeanDefinition 们,具体提的类实现不同的方法
loadBeanDefinitions(beanFactory);
// 加锁防止
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}
2-5(重点)执行AbstractXmlApplicationContext类的loadBeanDefinitions(DefaultListableBeanFactory beanFactory)

该方法是加载/解析Bean元数据信息的方法,此时Spring的容器已经创建好,会把所有的Bean封装成BeanDefiniton(Bean元数据信息)放入容器中。

该方法也有很多个实现,调试代码用的是ClassPathXmlApplicationContext类所以具体实现是在AbstractXmlApplicationContext类中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建一个 XmlBeanDefinitionReader XML解析器对象 , 需要一个 beanFactory
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 在实例化 AbstractRefreshableConfigApplicationContext 时 就已经设置了 Environment 属性
beanDefinitionReader.setEnvironment(this.getEnvironment());
// 容器应用上下文对象自身 也是 一个 ResourceLoader 类型
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);
/**
* 装载 BeanDefinitions 最后调用的 XmlBeanDefinitionReader#loadBeanDefinitions()方法
*/
loadBeanDefinitions(beanDefinitionReader);
}

方法中主要操作

  1. new XmlBeanDefinitionReader(beanFactory) 创建一个 XmlBeanDefinitionReader XML解析对象
  2. beanDefinitionReader.setEnvironment(this.getEnvironment()) ,给解析对象设置运行环境对象,此时this.getEnvironment()是有返回值的,详情请看上篇博客的``getEnvironment()方法介绍
  3. beanDefinitionReader.setResourceLoader(this)设置资源加载器,此时的this就是ClassPathXmlApplication对象,因为到现在代码依然在ClassPathXmlApplication的构造方法中。因为ClassPathXmlApplication间接实现了ResourceLoader接口(Spring统一资源加载器,用来获取资源对象Resource这篇博客有详细介绍ResourceLoader
  4. loadBeanDefinitions(beanDefinitionReader) 装载所有BeanDefinitions(Bean的元数据信息对象)
2-5-1: 执行AbstractXmlApplicationContext类的loadBeanDefinitions(XmlBeanDefinitionReader reader)方法

该方法中有两个操作

  1. 获取Resource资源文件,通过getConfigResources()getConfigLocations()方法。其中getConfigLocations()有返回值的(看[Spring IOC 源码调试一]的setConfigLocations(@Nullable String... locations)部分)。
  2. reader.loadBeanDefinitions(configLocations)将加载/解析 xml中bean对象的任务委托给了XmlBeanDefinitionReader对象
1
2
3
4
5
6
7
8
9
10
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);
}
}
2-5-2:执行AbstractBeanDefinitionReaderloadBeanDefinitions(String... locations)方法

虽然把加载/解析 xml中bean对象的任务委托给了XmlBeanDefinitionReader对象,但是该方法的具体实现被封装在了XmlBeanDefinitionReader父类AbstractBeanDefinitionReader中。

AbstractBeanDefinitionReader-loadBeanDefinitions.png

该方法中又是层层调用AbstractBeanDefinitionReaderloadBeanDefinitions重载方法,最后进入到loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources)方法中

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
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
//初始化 XmlBeanDefinitionReader 时 设置了 setResourceLoader(this)
ResourceLoader resourceLoader = getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException("Cannot load bean definitions from location [" + location + "]: no ResourceLoader available");
}
if (resourceLoader instanceof ResourcePatternResolver) {
// Resource pattern matching available.
try {
Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);
int count = loadBeanDefinitions(resources);
if (actualResources != null) {
Collections.addAll(actualResources, resources);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location pattern [" + location + "]");
}
return count;
}
catch (IOException ex) {
throw new BeanDefinitionStoreException(
"Could not resolve bean definition resource pattern [" + location + "]", ex);
}
}
else {
// Can only load single resources by absolute URL.
Resource resource = resourceLoader.getResource(location);
int count = loadBeanDefinitions(resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (logger.isTraceEnabled()) {
logger.trace("Loaded " + count + " bean definitions from location [" + location + "]");
}
return count;
}
}

由于篇幅原因loadBeanDefinitions方法到下篇博客继续跟踪……

总结

  1. Spring容器的具体实现对象是DefaultListableBeanFactory

  2. 加载/解析我们配置bean对象的xml文件的类的对象是XmlBeanDefinitionReader对象(这样说可能不太准确,但是解析入口是在该对象中开始的)

欢迎扫码关注

如果喜欢请关注我公众号【程序倾听者】,说出你的故事!我在这里倾听!

顶我一下下!
  • 版权声明: 本博客所有文章除特别声明外,著作权归作者所有。转载请注明出处!
  • Copyrights © 2015-2021 ListenerSun
  • 访问人数: | 浏览次数:

请我吃个棒棒糖可否~

支付宝
微信