这里先从ClassPathXmlApplicationContext的构造来开始分析
看一下 ClassPathXmlApplicationContext 的UML类图

1
2
3
4
5
6
7
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, @Nullable ApplicationContext parent) throws BeansException {
super(parent);
this.setConfigLocations(configLocations);
if (refresh) {
this.refresh();
}
}

看super(parent)做了些什么,parent卡是传进来的是null

1
2
3
4
public AbstractApplicationContext(@Nullable ApplicationContext parent) {
this();
this.setParent(parent);
}

看this()

1
2
3
4
5
6
7
8
9
10
11
public AbstractApplicationContext() {
this.logger = LogFactory.getLog(this.getClass());
this.id = ObjectUtils.identityToString(this);
this.displayName = ObjectUtils.identityToString(this);
this.beanFactoryPostProcessors = new ArrayList();
this.active = new AtomicBoolean();
this.closed = new AtomicBoolean();
this.startupShutdownMonitor = new Object();
this.applicationListeners = new LinkedHashSet();
this.resourcePatternResolver = this.getResourcePatternResolver();
}

这里给当前类(AbstractApplicationContext)的私有变量初始化值。看看setParent()做了些什么

1
2
3
4
5
6
7
8
9
10
11
public void setParent(@Nullable ApplicationContext parent) {
this.parent = parent;
// 当parent不为空的时候,会对IOC环境进行配置。
if (parent != null) {
Environment parentEnvironment = parent.getEnvironment();
if (parentEnvironment instanceof ConfigurableEnvironment) {
this.getEnvironment().merge((ConfigurableEnvironment)parentEnvironment);
}
}
}

这里super(parent)已经执行完了,继续往下看this.setConfigLocations(configLocations);

1
2
3
4
5
6
7
8
9
10
11
12
public void setConfigLocations(@Nullable 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] = this.resolvePath(locations[i]).trim();
}
} else {
this.configLocations = null;
}
}

这里会解析传进来的配置文件路径参数,用的是ant规则匹配。解析完后将路径信息放入configLocations数组里面。往下看refresh默认是true,看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
public void refresh() throws BeansException, IllegalStateException {
// var1 = new Object
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
// 调用容器准备刷新的方法,此方法中会获取容器的当前时间,给容器设置同步标识
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
// beanFactory的后置处理器
this.postProcessBeanFactory(beanFactory);
//调用BeanFactoryPostProcessor,激活各种BeanFactory处理器
this.invokeBeanFactoryPostProcessors(beanFactory);
//注册拦截Bean创建的Bean处理器,这里只是注册,真正调用是在getBean的时候。
this.registerBeanPostProcessors(beanFactory);
//为上下文初始化Message源,国际化处理
this.initMessageSource();
//初始化应用消息广播器,并放入applicationEventMulticaster bean中
this.initApplicationEventMulticaster();
//留给子类来初始化其他的Bea
this.onRefresh();
//在所有注册的bean中查找Listener bean,注册到消息广播器中
this.registerListeners();
//初始化剩下的单实例,非惰性的
this.finishBeanFactoryInitialization(beanFactory);
//完成刷新过程,通知生命周期处理器lifecycleProcessor刷新过程,同时发出ContextRefreshEvent通知别人
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}

这里重点看一下 obtainFreshBeanFactory 方法,它返回一个beanFactory对象,那么我们这里可以猜测应该读取了配置文件,配置了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
27
28
29
30
31
32
33
34
35
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
this.refreshBeanFactory();
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
if (this.logger.isDebugEnabled()) {
this.logger.debug("Bean factory for " + this.getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}
```
这里首先调用 refreshBeanFactory 方法刷新beanFactory。源码如下:
```java
protected final void refreshBeanFactory() throws BeansException {
if (this.hasBeanFactory()) {
this.destroyBeans();
this.closeBeanFactory();
}
try {
// 创建一个新的beanFacroty
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
// 配置beanFactory的属性
beanFactory.setSerializationId(this.getId());
this.customizeBeanFactory(beanFactory);
this.loadBeanDefinitions(beanFactory);
Object var2 = this.beanFactoryMonitor;
synchronized(this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException var5) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + this.getDisplayName(), var5);
}
}

可以看出,首先判断是否已经存在beanFactory,有就关闭,然后再创建一个beanFactory.看一下创建 createBeanFactory 的具体实现

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

由于前面的parent参数为null,所以这个 getInternalParentBeanFactory 方法返回值为null。这里就实例化了一个 DefaultListableBeanFactory 工厂类。回到前面继续往下看, customizeBeanFactory 方法内部是判断变量赋值的,这里条件都不满足,继续往下看,loadBeanDefinitions 方法是负责给 beanFactory 填充 bean 定义的,看看源码

1
2
3
4
5
6
7
8
9
10
11
12
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 创建 XML 读取器
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 配置 beanDefinitionReader
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 对读取器 设置xml校验。
this.initBeanDefinitionReader(beanDefinitionReader);
// 读取配置文件,加载 bean 的定义
this.loadBeanDefinitions(beanDefinitionReader);
}

看一下 loadBeanDefinitions 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// Resource 是将配置文件封装的一个对象,首先尝试能否直接获取到 Resource 数组。默认是不行的
Resource[] configResources = this.getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
// 这里就直接获取配置文件的 localtion,后面还是先获取到Resource[] 数组再去读取xml文件
String[] configLocations = this.getConfigLocations();
if (configLocations != null) {
reader.loadBeanDefinitions(configLocations);
}
}

看看 loadBeanDefinitions(configLocations) 的源码,实际调用的是下面这个重载类

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
public int loadBeanDefinitions(String location, @Nullable Set<Resource> actualResources) throws BeanDefinitionStoreException {
// 获取 ResourceLoader 加载器
ResourceLoader resourceLoader = this.getResourceLoader();
if (resourceLoader == null) {
throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
} else {
int loadCount;
if (!(resourceLoader instanceof ResourcePatternResolver)) {
Resource resource = resourceLoader.getResource(location);
loadCount = this.loadBeanDefinitions((Resource)resource);
if (actualResources != null) {
actualResources.add(resource);
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
}
return loadCount;
} else {
try {
Resource[] resources = ((ResourcePatternResolver)resourceLoader).getResources(location);
// 这里对配置文件进行读取,返回读取的配置文件数量
loadCount = this.loadBeanDefinitions(resources);
if (actualResources != null) {
Resource[] var6 = resources;
int var7 = resources.length;
for(int var8 = 0; var8 < var7; ++var8) {
Resource resource = var6[var8];
actualResources.add(resource);
}
}
if (this.logger.isDebugEnabled()) {
this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
}
return loadCount;
} catch (IOException var10) {
throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
}
}
}
}

细看读取过程

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
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (this.logger.isInfoEnabled()) {
this.logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
Set<EncodedResource> currentResources = (Set)this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!((Set)currentResources).add(encodedResource)) {
throw new BeanDefinitionStoreException("Detected cyclic loading of " + encodedResource + " - check your import definitions!");
} else {
int var5;
try {
// 获取文件流
InputStream inputStream = encodedResource.getResource().getInputStream();
try {
InputSource inputSource = new InputSource(inputStream);
if (encodedResource.getEncoding() != null) {
inputSource.setEncoding(encodedResource.getEncoding());
}
// 这里加载配置文件
var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
} finally {
inputStream.close();
}
} catch (IOException var15) {
throw new BeanDefinitionStoreException("IOException parsing XML document from " + encodedResource.getResource(), var15);
} finally {
((Set)currentResources).remove(encodedResource);
if (((Set)currentResources).isEmpty()) {
this.resourcesCurrentlyBeingLoaded.remove();
}
}
return var5;
}
}

来看一下怎么加载的,这个 doLoadBeanDefinitions 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
// 理论上一个 inputSource 参数就行了,为什么还要 resource 呢?这里是为了设置xml验证模式引入的。这个方法就将InputSource对象转变成了 Document 对象。
Document doc = this.doLoadDocument(inputSource, resource);
// 这个方法将document对象变成了Bean放入内存中
return this.registerBeanDefinitions(doc, resource);
} catch (BeanDefinitionStoreException var4) {
throw var4;
} catch (SAXParseException var5) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "Line " + var5.getLineNumber() + " in XML document from " + resource + " is invalid", var5);
} catch (SAXException var6) {
throw new XmlBeanDefinitionStoreException(resource.getDescription(), "XML document from " + resource + " is invalid", var6);
} catch (ParserConfigurationException var7) {
throw new BeanDefinitionStoreException(resource.getDescription(), "Parser configuration exception parsing XML from " + resource, var7);
} catch (IOException var8) {
throw new BeanDefinitionStoreException(resource.getDescription(), "IOException parsing XML document from " + resource, var8);
} catch (Throwable var9) {
throw new BeanDefinitionStoreException(resource.getDescription(), "Unexpected exception parsing XML document from " + resource, var9);
}
}

看一下这个方法 registerBeanDefinitions

1
2
3
4
5
6
7
8
public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {
// 获取一个专为 BeanDefinitionDocument 的 reader。
BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
int countBefore = this.getRegistry().getBeanDefinitionCount();
// 这里就是开始读取xml定义的文件了
documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
return this.getRegistry().getBeanDefinitionCount() - countBefore;
}

看一下读取方法 registerBeanDefinitions 的细节

1
2
3
4
5
6
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
this.logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
this.doRegisterBeanDefinitions(root);
}

看具体加载根节点的方法 doRegisterBeanDefinitions

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
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
String profileSpec = root.getAttribute("profile");
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
if (!this.getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
if (this.logger.isInfoEnabled()) {
this.logger.info("Skipped XML bean definition file due to specified profiles [" + profileSpec + "] not matching: " + this.getReaderContext().getResource());
}
return;
}
}
}
//xml解析的预处理,可以自己定义一些节点属性等,此方法Spring默认实现为空
this.preProcessXml(root);
//把Document对象解析为BeanDefinition对象
this.parseBeanDefinitions(root, this.delegate);
//xml解析的后处理,可以在解析完xml之后,实现自己的逻辑。Spring默认实现为空。
this.postProcessXml(root);
this.delegate = parent;
}

看一下parseBeanDefinitions方法源码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
// 判断是不是Spring的默认空间命名(dubbo的就不是)
if (delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for(int i = 0; i < nl.getLength(); ++i) {
Node node = nl.item(i);
if (node instanceof Element) {
Element ele = (Element)node;
if (delegate.isDefaultNamespace(ele)) {
this.parseDefaultElement(ele, delegate);
} else {
delegate.parseCustomElement(ele);
}
}
}
} else {
// dubbo配置文件读取就是从这里开始的
delegate.parseCustomElement(root);
}
}

到这里为止就差不多了,SpringIOC里面配置的bean就是这么来的。

总结

  • IOC容器初始化入口是在构造方法中调用refresh开始的。
  • 通过ResourceLoader来完成资源文件位置的定位,DefaultResourceLoader是默认的实现,同时上下文本身就给除了ResourceLoader的实现。
  • 创建的IOC容器是DefaultListableBeanFactory。
  • IOC对Bean的管理和依赖注入功能的实现是通过对其持有的BeanDefinition进行相关操作来完成的。
  • 通过BeanDefinitionReader来完成定义信息的解析和Bean信息的注册。
  • XmlBeanDefinitionReader是BeanDefinitionReader的实现了,通过它来解析xml配置中的bean定义。
  • 实际的处理过程是委托给BeanDefinitionParserDelegate来完成的。得到Bean的定义信息,这些信息在Spring中使用BeanDefinition对象来表示。
  • BeanDefinition的注册是由BeanDefinitionRegistry实现的registerBeanDefiition方法进行的。内部使用ConcurrentHashMap来保存BeanDefiition。