这篇文章接着上篇Spring IOC实现原理笔记(一)的测试代码,从ClassPathXmlApplicationContext开始分析spring的装载对象到容器的实现。
先放出继承图,对源码跟踪有帮助
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[]{configLocation}, true, (ApplicationContext)null);
}
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException {
super(parent);//设置父ApplicationContext
this.setConfigLocations(configLocations);//设置配置文件路径
if(refresh) {
this.refresh();
}
}
有点意外,逻辑这么简单,然后跟踪refresh方法进去,跳到了AbstractApplicationContext类,然后就头大了,如下
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();//步骤1:准备刷新上下文环境
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();//步骤2:初始化BeanFactory,并进行XML文件读取
this.prepareBeanFactory(beanFactory);//步骤3:对BeanFactory各种功能填充
try {
this.postProcessBeanFactory(beanFactory);//步骤4:子类富态方法做额外的处理
this.invokeBeanFactoryPostProcessors(beanFactory);//步骤5:激活各种BeanFactory处理器
this.registerBeanPostProcessors(beanFactory);//步骤6:注册拦截Bean创建的Bean处理器
this.initMessageSource();//步骤7:为上下文初始化Message源,即国际化处理
this.initApplicationEventMulticaster();//步骤8:初始化应用消息广播器
this.onRefresh();//步骤9:留给子类具体实现
this.registerListeners();//步骤10:注册消息广播器
this.finishBeanFactoryInitialization(beanFactory);//步骤11:初始化剩余的单实例(非惰性)
this.finishRefresh();//步骤12:完成刷新过程,通知生命周期处理器,发出刷新事件
} catch (BeansException var9) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt", var9);
this.destroyBeans();//步骤14
this.cancelRefresh(var9);//步骤15
throw var9;
} finally {
this.resetCommonCaches();//步骤13:清理缓存
}
}
}
因为本篇只写关于加载XML配置信息,而上面的【步骤2】就做了这一步工作,跟踪进去
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
this.refreshBeanFactory();//这里开始初始化BeanFactory并解析XML信息
ConfigurableListableBeanFactory beanFactory = this.getBeanFactory();
return beanFactory;
}
protected final void refreshBeanFactory() throws BeansException {
if(this.hasBeanFactory()) {//销毁原有的BeanFactory
this.destroyBeans();
this.closeBeanFactory();
}
try {
DefaultListableBeanFactory beanFactory = this.createBeanFactory();
beanFactory.setSerializationId(this.getId());
this.customizeBeanFactory(beanFactory);
this.loadBeanDefinitions(beanFactory);//进入解析XML阶段
Object var2 = this.beanFactoryMonitor;
synchronized(this.beanFactoryMonitor) {
this.beanFactory = beanFactory;
}
} catch (IOException var5) {
...
}
}
可以看到refreshBeanFactory方法会把当前的BeanFactory销毁,然后初始化一个DefaultListableBeanFactory实例(作为AbstractRefreshableApplicationContext的一个成员变量)。
DefaultListableBeanFactory继承图如下
接下来跟踪解析XML阶段:loadBeanDefinitions(beanFactory);
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));//为解决联网获取xsd,dtd文件的问题
this.initBeanDefinitionReader(beanDefinitionReader);
this.loadBeanDefinitions(beanDefinitionReader);
}
上面看到创建了一个XmlBeanDefinitionReader实例,并持有beanFactory的引用(构造方法传入的)。XmlBeanDefinitionReader就是用于解析XML,并把解析的bean封装成BeanDefinitionHolder,然后传给BeanDefinitionRegistry(实际就是DefaultListableBeanFactory),进行相关的缓存。
下面出场的是XML解析的主力XmlBeanDefinitionReader
...上面的loadBeanDefinitions方法,经过山路十八弯,最终进入下面的方法
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
try {
//解析XML成一个Document(包:org.w3c.dom)对象
Document doc = this.doLoadDocument(inputSource, resource);
//解析内容封装成BeanDefinitionHolder,然后放入BeanDefinitionRegistry中缓存起来
return this.registerBeanDefinitions(doc, resource);
} catch...
}
最终解析会进入下面的方法
protected void doRegisterBeanDefinitions(Element root) {
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = this.createDelegate(this.getReaderContext(), root, parent);
//先判断profile属性进行判断是否符合,不符合就退出不用解析了
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)) {
return;
}
}
}
...
this.parseBeanDefinitions(root, this.delegate);//开始解析
...
}
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);
}
}
对XML解析分两种情况,第一是对默认节点的解析(如bean,alias,import,beans等),第二是对自定义节点的解析(如tx,p,aop等)。解析得到的bean的相关配置信息封装成BeanDefinitionHolder,然后传给BeanDefinitionRegistry(实际就是DefaultListableBeanFactory,可从继承图看到出),进行相关缓存操作。
如果是解析自定义节点则是需要有相对应的NamespaceHandler,后续分析AOP,会分析NamespaceHandler
//解析默认节点
private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
if(delegate.nodeNameEquals(ele, "import")) {
this.importBeanDefinitionResource(ele);
} else if(delegate.nodeNameEquals(ele, "alias")) {
this.processAliasRegistration(ele);
} else if(delegate.nodeNameEquals(ele, "bean")) {
this.processBeanDefinition(ele, delegate);
} else if(delegate.nodeNameEquals(ele, "beans")) {
this.doRegisterBeanDefinitions(ele);
}
}
//解析自定义节点
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
String namespaceUri = this.getNamespaceURI(ele);
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
if(handler == null) {
...
return null;
} else {
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
}
看一下BeanDefinitionHolder类
public class BeanDefinitionHolder implements BeanMetadataElement {
private final BeanDefinition beanDefinition;
private final String beanName;
private final String[] aliases;
...
}
它记录了一个bean的配置信息,还有bean的名称、别名,通过它可以把一个bean的配置信息,别名缓存到BeanDefinitionRegistry
总结:
XML解析主要用了SAX技术解析,然后把解析的bean的信息封装成BeanDefinition存入BeanDefinitionRegistry中,方便之后从容器中获取实例时根据解析好的信息进行实例化。当然由于Spring提供了多种强大的配置,其中解析的过程并不轻松,要经过很多逻辑的处理。
在Spring IOC实现原理笔记(一)中有一个BeanFactoryPostProcessor实例,它在哪里被调用的呢?其实就在【步骤5】
this.invokeBeanFactoryPostProcessors(beanFactory);
参考:
Spring源码(4.2.2.RELEASE)
《Spring源码深度解析》