这里先从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;
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 {
Object var1 = this .startupShutdownMonitor;
synchronized (this .startupShutdownMonitor) {
this .prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this .obtainFreshBeanFactory();
this .prepareBeanFactory(beanFactory);
try {
this .postProcessBeanFactory(beanFactory);
this .invokeBeanFactoryPostProcessors(beanFactory);
this .registerBeanPostProcessors(beanFactory);
this .initMessageSource();
this .initApplicationEventMulticaster();
this .onRefresh();
this .registerListeners();
this .finishBeanFactoryInitialization(beanFactory);
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 {
DefaultListableBeanFactory beanFactory = this .createBeanFactory();
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 {
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
beanDefinitionReader.setEnvironment(this .getEnvironment());
beanDefinitionReader.setResourceLoader(this );
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this ));
this .initBeanDefinitionReader(beanDefinitionReader);
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[] configResources = this .getConfigResources();
if (configResources != null ) {
reader.loadBeanDefinitions(configResources);
}
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 = 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 {
Document doc = this .doLoadDocument(inputSource, resource);
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 {
BeanDefinitionDocumentReader documentReader = this .createBeanDefinitionDocumentReader();
int countBefore = this .getRegistry().getBeanDefinitionCount();
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 ;
}
}
}
this .preProcessXml(root);
this .parseBeanDefinitions(root, this .delegate);
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) {
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 {
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。
Read More