1. 概述
创建容器对象DefaultListableBeanFactory,通过loadBeanDefinitions(beanFactory)初始胡documentReader,并对xml文件(及其它文件)读取及解析,包含默认命名空间的解析,自定义标签的解析(以xml为例子)
2. 源码分析
2.1 obtainFreshBeanFactory()
-> 执行获取新鲜的工厂。
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
/=====================
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
// 初始化BeanFactory,并进行XML文件读取,解析
//并将得到的BeanFactory记录在AbstractRefreshableApplicationContext的属性中
refreshBeanFactory();
// 返回当前实体的beanFactory属性
return getBeanFactory();
}
2.2 refreshBeanFactory()
AbstractRefreshableApplicationContext.java
@Override
protected final void refreshBeanFactory() throws BeansException {
// 如果存在beanFactory,则销毁beanFactory
if (hasBeanFactory()) {
destroyBeans();
closeBeanFactory();
}
try {
// 创建DefaultListableBeanFactory对象;全是空的属性
DefaultListableBeanFactory beanFactory = createBeanFactory();
// 为了序列化指定id,可以从id反序列化到beanFactory对象
beanFactory.setSerializationId(getId());
// 定制beanFactory,设置相关属性,包括是否允许覆盖同名称的不同定义的对象(bean信息覆盖)以及循环依赖。
// allowCircularReferences 同名属性在 AbstractRefreshableApplicationContext类中和 DefaultListableBeanFactory都有。
//子类复写了,调用子类的
customizeBeanFactory(beanFactory);
// 初始化documentReader,并进行XML文件读取及解析,默认命名空间的解析,自定义标签的解析
loadBeanDefinitions(beanFactory);
this.beanFactory = beanFactory;
}
//.....
}
2.3 loadBeanDefinitions(beanFactory);
AbstractXmlApplicationContext.java
@Override
protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws BeansException, IOException {
// 为给定的BeanFactory创建一个xml的beanDefinitionReader.并通过回调设置到beanFactory中
XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
// 给reader对象设置环境对象
beanDefinitionReader.setEnvironment(this.getEnvironment());
beanDefinitionReader.setResourceLoader(this);
beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));
// 初始化beanDefinitionReader对象,此处设置配置文件是否要进行验证
initBeanDefinitionReader(beanDefinitionReader);
// 开始完成beanDefinition的加载
loadBeanDefinitions(beanDefinitionReader);
}
//==============================
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {
// 以Resource的方式获得配置文件的资源位置
Resource[] configResources = getConfigResources();
if (configResources != null) {
reader.loadBeanDefinitions(configResources);
}
// 以String的形式获得配置文件的位置
String[] configLocations = getConfigLocations();
if (configLocations != null) {
//通过reader 开始向下处理
reader.loadBeanDefinitions(configLocations);
}
}
2.3 loadBeanDefinitions(…)
AbstracttBeanDefinitionReader.java
资源经过变化,转化成可处理的Resource对象。
从String[] -string-Resource[]- resource
2.4 doLoadBeanDefinitions
XmlBeanDefinitionReader.java
进过上面的转化,到了处理的核心步骤
protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)
// 此处获取xml文件的document对象,
// 这个解析过程是由documentLoader完成的,最终开始将resource读取成一个document文档,
Document doc = doLoadDocument(inputSource, resource);
// 根据文档的节点信息封装成一个个的
//BeanDefinition对象
int count = registerBeanDefinitions(doc, resource);
return count;
//==============================
public int registerBeanDefinitions(Document doc, Resource resource)
// 对xml的beanDefinition进行解析
BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();
int countBefore = getRegistry().getBeanDefinitionCount();
// 通过documentReader完成具体的解析过程。将beanDefinition注册进beanFactory中
documentReader.registerBeanDefinitions(doc, createReaderContext(resource));
return getRegistry().getBeanDefinitionCount() - countBefore;
}
2.5 registerBeanDefinitions
DefaultBeanDefinitionDocumentReader
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
doRegisterBeanDefinitions(doc.getDocumentElement());
}
//========================
//开始真正的去解析
==>parseBeanDefinitions(root, this.delegate);
//============================
//遍历每一个节点的信息,判断使用默认的解析方法,还是自定义的解析方法
if (delegate.isDefaultNamespace(ele)) {
//默认,import 、alais、bean、beans 标签使用默认解析器
parseDefaultElement(ele, delegate);}
else {
//根据命名空间获取处理器,在处理器中根据属性标签,获取解析器,解析
delegate.parseCustomElement(ele);}
2.5 parse
2.5.1 使用默认的解析器,解析bean标签
解析完成,封装成beanDefination,并将结果存储到DefaultListableBeanFactory中,供以后使用。
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
2.5.2 使用自定义的解析器
本例通过Context 标签。
@Nullable
public BeanDefinition parseCustomElement(Element ele, @Nullable BeanDefinition containingBd) {
// 获取对应的命名空间
String namespaceUri = getNamespaceURI(ele);
// 根据命名空间找到对应的NamespaceHandler ,且执行了将解析器放入parses 属性中.
//NamespaceHandlerSupport->
// private final Map<String, BeanDefinitionParser> parsers = new HashMap<>();
//供以后通过名称查找对应的解析器
NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
//举例使用ContextNamespaceHandler ,里面包含很多解析器
// 调用自定义的NamespaceHandler进行解析。通过findParserForElement,找到对应的解析器
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
3. 思考
- 加载->注册->解析,依次递进的过程