int n=reader.loadBeanDefinitions(res); //触发,XmlBeanDefinitionReader加载,解析配置文件,生成BeanDefinition的动作
B b=(B) factory.getBean("b");
以下分析这部分源码.
首先说明DefaultListableBeanFactory实现了BeanDefinitionRegistry接口,代表一个能够存放BeanDefinition的容器。
XmlBeanDefinitionReader是个beanDefinition读取器,完成配置文件定位,加载分析,生成beanDefinition及注册到容器中(这几个任务单独交由不同组件去做)。
XmlBeanDefinitionReader已经有个元素就是beanRegistry容器。因此XmlBeanDefinitionReader reader=new XmlBeanDefinitionReader(factory) 只是将容器设置
到XmlBeanDefinitionReader的registry属性上。
接着调用XmlBeanDefinitionReader的loadBeanDefinitions,开始对于ClassPathResource的资源的定位,加载分析等后续操作。
源码如下:
public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
return loadBeanDefinitions(new EncodedResource(resource));
}
可以看到这里,对于resource这里又封装成EncodedResource,这个EncodedResource封装了encoding,用于在读取流的时候采用何种编码。
接着将EncodedResource传给loadBeanDefinitions方法。
在看loadBeanDefinitions方法前,不妨先问自己一个问题,如果在当前containerTest.xml文件中又import了containerTest.xml会怎么样?
理论上,是要报错的,如果是这样,如何做?
loadBeanDefinitions方法如下:
public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
Assert.notNull(encodedResource, "EncodedResource must not be null");
if (logger.isInfoEnabled()) {
logger.info("Loading XML bean definitions from " + encodedResource.getResource());
}
/**
这里的set,解决了资源文件重复引用的问题
通过将EncodedResource放入一个集合set,然后将将这个set放入到一个
ThreadLocal当中:ThreadLocal<Set<EncodedResource>> resourcesCurrentlyBeingLoaded
每次加载新资源文件就将其放入到这个集合中,如果已经存在,放入失败则抛出异常
**/
Set<EncodedResource> currentResources = this.resourcesCurrentlyBeingLoaded.get();
if (currentResources == null) {
currentResources = new HashSet<EncodedResource>(4);
this.resourcesCurrentlyBeingLoaded.set(currentResources);
}
if (!currentResources.add(encodedResource)) {
throw new BeanDefinitionStoreException(
"Detected cyclic loading of " + encodedResource + " - check your import definitions!");
}
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
很简单,这个方法获取doc文档中的根元素,为 [beans]。
然后调用doRegisterBeanDefinitions进行处理,代码如下:
protected void doRegisterBeanDefinitions(Element root) {
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
Assert.state(this.environment != null, "environment property must not be null");
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(profileSpec, `` BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!this.environment.acceptsProfiles(specifiedProfiles)) {
return;
}
}
// any nested <beans> elements will cause recursion in this method. In
// order to propagate and preserve <beans> default-* attributes correctly,
// keep track of the current (parent) delegate, which may be null. Create
// the new (child) delegate with a reference to the parent for fallback purposes,
// then ultimately reset this.delegate back to its original (parent) reference.
// this behavior emulates a stack of delegates without actually necessitating one.
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createHelper(readerContext, root, parent);