Spring 源码解析二(BeanFactory的创建)

引言

在第二期介绍容器的refresh方法开始之前,首先大家应该对Spring容器的整个继承体系有个大概的了解,不然就会有雾里看花的感觉

  • 为了帮助大家理清整个继承体系,我将接下来所要涉及到的几个重要类及接口的继承关系贴上来,在阅读中如有疑惑的话,可以回过头来看看这几张图
XmlWebApplicationContext

由web容器启动的Spring容器类,注意与DefaultListableBeanFactory的区别
image.png

DefaultListableBeanFactory

实际实现的bean工厂类,获取bean操作的方法都在这里
image.png

XmlBeanDefinitionReader

读取我们配置文件信息
image.png

BeanFactory 接口及其实现

由以上图中可以看出,BeanFactory 接口定义了IOC容器最基本的功能规范,是每一个IOC容器都要遵守的基本规范。其中最重要的就是定义了getBean方法,让我们可以从容器中根据名字拿到所需要的bean。 DefaultListableBeanFactory就是其一个重要实现,与我们接触也是最多的,而XmlWebApplicationContext可以理解为一个更高级的IOC容器,除支持BeanFactory的基本功能外,还提供了很多扩展功能

容器 refresh 方法

接着上节继续往下讲
refresh 是整个容器启动的核心方法,在AbstractApplicationContext中,其做的事情主要有三个:

  • BeanFactory的创建(DefaultListableBeanFactory)
  • BeanDefinition的Resource定位,载入,和注册
  • 在实例化Bean之前对BeanDefinition进行修改(调用实现了接口BeanFactoryPostProcessorBeanDefinitionRegistryPostProcessor的类)
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
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();

// 创建BeanFactory,并载入BeanDefinitions(重要)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);

// 执行 BeanFactoryPostProcessors
invokeBeanFactoryPostProcessors(beanFactory);

// 注册 BeanPostProcessors
registerBeanPostProcessors(beanFactory);

// Initialize message source for this context.
initMessageSource();

// Initialize event multicaster for this context.
initApplicationEventMulticaster();

// Initialize other special beans in specific context subclasses.
onRefresh();

// Check for listener beans and register them.
registerListeners();

// 提前实例化化全部延迟加载的单例类型
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();
}
}
}

obtainFreshBeanFactory()

obtainFreshBeanFactory() 也在 AbstractApplicationContext类中,主要逻辑在refreshBeanFactory 方法中

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() (AbstractRefreshableApplicationContext)

这里做的事情主要有2个:

1.创建BeanFactory (createBeanFactory())
2.载入BeanDefinitions (loadBeanDefinitions(beanFactory))

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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);
}
}

createBeanFactory()

从这里可以知道容器所使用的BeanFactory实现类是 DefaultListableBeanFactory

1
2
3
protected DefaultListableBeanFactory createBeanFactory() {
return new DefaultListableBeanFactory(getInternalParentBeanFactory());
}

loadBeanDefinitions(beanFactory) (XmlWebApplicationContext)

这个方法是在XmlWebApplicationContext实现的,Spring随处可见父类调用子类的设计模式(模板方法设计模式)

在解析loadBeanDefinitions方法之前,有必要先了解BeanDefinition在Spring中所表示的概念 (通俗的理解可以说是bean的抽象数据结构,它包括属性参数,构造器参数,以及其他具体的参数,就是我们从配置信息中读出来Bean的抽象数据结构)有兴趣的可以去看看BeanDefinition的数据结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建一个XmlBeanDefinitionReader,用来读取配置文件配置的Bean信息,解析成beanDefinition,并配置beanFactory 方便回调
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

// 配置XmlBeanDefinitionReader的一些基本配置
beanDefinitionReader.setEnvironment(getEnvironment());
// 配置ResourceLoader(XmlWebApplicationContext 是实现了ResourceLoader接口的,不清楚的可以上图的继承链)
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

// Allow a subclass to provide custom initialization of the reader,
// 这里没做任何事情
initBeanDefinitionReader(beanDefinitionReader);
loadBeanDefinitions(beanDefinitionReader);
}

loadBeanDefinitions(XmlBeanDefinitionReader reader)

XmlBeanDefinitionReader 根据配置文件位置调用 loadBeanDefinitions

1
2
3
4
5
6
7
8
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws IOException {
String[] configLocations = getConfigLocations();
if (configLocations != null) {
for (String configLocation : configLocations) {
reader.loadBeanDefinitions(configLocation);
}
}
}

尾言

到目前为止,我们知道了IOC容器的创建,以及BeanDefinition是在哪里被加载的。接下来要讲的自然就是配置信息是如何被解析加载的,以及如何注册进BeanFactory的。see => 下期

Powered by Hexo and Hexo-theme-hiker

Copyright © 2013 - 2020 王俊男的技术杂谈 All Rights Reserved.

访客数 : | 访问量 :