在Spring中,容器的加载一般是经过如下过程
1.创建Beanfactory对象
2.调用Beanfactory对象的initBeanDefinitionReader
3.调用Beanfactory对象的loadBeanDefinitions
一. initBeanDefinitionReader
1.1 构造XmlBeanDefinitionReader,在这个对象中构造了errorHandler, validationModeDetector, resourcesCurrentlyBeingLoaded,设置当前的registry
this.errorHandler =newSimpleSaxErrorHandler(this.logger);
this.validationModeDetector =newXmlValidationModeDetector();
this.resourcesCurrentlyBeingLoaded =newNamedThreadLocal("XML bean definition resources currently being loaded");
1.2 setValidating(boolean)
二. loadBeanDefinitions
2.1 入口
Resource[] configResources =this.getConfigResources();
if(configResources !=null) {
reader.loadBeanDefinitions(configResources);
}
String[] configLocations =this.getConfigLocations();
if(configLocations !=null) {
reader.loadBeanDefinitions(configLocations);
}
2.2 进一步处理流程如下
for(int var5 = 0; var5 < var4; ++var5) {
String location = var3[var5];
counter += this.loadBeanDefinitions(location);
}
2.3 进一步处理流程如下:
return this.loadBeanDefinitions(location,(Set)null);
进一步处理调用流程为AbstractBeanDefinitionReader的loadBeanDefinitions(String location, Set
2.3.1 在这里又会执行如下操作
2.3.1.1 首先获得resourceLoader
2.3.1.2 如果resource的模式不是ResourcePatternResolver, 说明是单个resource, 执行一些操作
if(!(resourceLoaderinstanceofResourcePatternResolver)) {
Resource var11 = resourceLoader.getResource(location);
loadCount =this.loadBeanDefinitions((Resource)var11);
if(actualResources !=null) {
actualResources.add(var11);
}
2.3.1.3 如果resource的模式是ResourcePatternResolver, 说明是多个resource, 执行另外一些操作
try{
Resource[] resource = ((ResourcePatternResolver)resourceLoader).getResources(location);
loadCount =this.loadBeanDefinitions(resource);
if(actualResources !=null) {
Resource[] var6 = resource;
int var7 = resource.length;
for(intvar8 =0;var8 < var7;++var8) {
Resource resource1 = var6[var8];
actualResources.add(resource1);
}
}
4. 在上述的2,3操作最终都会走到XmlBeanDefinitionReader的loadBeanDefinitions(Resource resource)函数,该函数执行如下操作
4.1. 根据Resource创建EncodedResource
4.2 查看当前resourcesCurrentlyBeingLoaded 这个set是不是包含了正在准备加载的resource
4.2.1 如果已经包含了,说明当前存在循环的import, 抛出异常
4.2.2 如果没有包含,则执行正常的流程
4.3 最终会走向doLoadBeanDefinitions函数,该函数位于XMlBeanDefinitionReader类中, 执行逻辑如下
1.获得validationMode (XSD和DTD 后续研究) 总之就是验证类型不是dtd就是xsd
2.执行DefaultDocumentLoader类的loadDocument函数
在该函数中, 需要使用EntityResolver获取加载dtd/xsd文件对xml文件进行校验,该处后续详细解释.
3.registerBeanDefinitions(document, resource)
3.1 首先创建BeanDefinitionDocumentReader
3.2 获取之前已经加载的bean数量
3.3 执行最终的逻辑 doRegisterBeanDefinitions(Element root)
3.3.1 首先获得profile属性,(root此时是根元素,一般是beans), 如果发现指定了profile,则把profile元素拆分出来,然后判断当前的环境是不是支持指定的profile
3.3.2 方法的preProcessXml和postProcessXml是空函数,因此是为了子类继承重写而来
3.3.3 最终执行逻辑在parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)中,执行逻辑是,1.
if(delegate.isDefaultNamespace(root)) {
NodeList nl = root.getChildNodes();
for(inti =0; i < nl.getLength(); ++i) {
Node node = nl.item(i);
if(nodeinstanceofElement) {
Element ele = (Element)node;
if(delegate.isDefaultNamespace(ele)) {
this.parseDefaultElement(ele, delegate);
}else{
delegate.parseCustomElement(ele);
}
}
}else{
delegate.parseCustomElement(root);
}
可见在此处,是执行parseDefaultElement或者是执行parseCustomElement走入了分歧,(DefaultBeanDefinitionDocumentReader)详见
<