引自 spring IoC源码分析 (3)Resource解析
定义好了Resource之后,看到XmlFactoryBean的构造函数
- public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {
- super(parentBeanFactory);
- this.reader.loadBeanDefinitions(resource);
- }
跟到XmlBeanDefinitionReader 的 loadBeanDefinitions(EncodedResource
encodedResource) 方法
- 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> currentResources = this.resourcesCurrentlyBeingLoaded.get();
- if (currentResources == null) {
- currentResources = new HashSet<EncodedResource>(4);
- this.resourcesCurrentlyBeingLoaded.set(currentResources);
- }
-
-
- if (!currentResources.add(encodedResource)) {
- throw new BeanDefinitionStoreException(
- "Detected recursive loading of " + encodedResource + " - check your import definitions!");
- }
- try {
- InputStream inputStream = encodedResource.getResource().getInputStream();
- try {
- InputSource inputSource = new InputSource(inputStream);
- if (encodedResource.getEncoding() != null) {
- inputSource.setEncoding(encodedResource.getEncoding());
- }
- return doLoadBeanDefinitions(inputSource, encodedResource.getResource());
- }
- finally {
- inputStream.close();
- }
- }
- catch (IOException ex) {
- throw new BeanDefinitionStoreException(
- "IOException parsing XML document from " + encodedResource.getResource(), ex);
- }
- finally {
- currentResources.remove(encodedResource);
- if (currentResources.isEmpty()) {
- this.resourcesCurrentlyBeingLoaded.set(null);
- }
- }
- }
其
实关键方法是 doLoadBeanDefinitions(inputSource, encodedResource.getResource())
,但是上面的注释绝对花了我将近1个钟头才理解作者想表达的意思,刚开始一看到ThreadLocal 就想到线程安全,然后就想currentResources
永远是线程安全的啊,丫就这么被带坑里去了。从上面可以看到关键方法是doLoadBeanDefinitions,这个方法的关键代码其实就几行
- try {
-
- int validationMode = getValidationModeForResource(resource);
- Document doc = this.documentLoader.loadDocument(
- inputSource, getEntityResolver(), this.errorHandler, validationMode, isNamespaceAware());
- return registerBeanDefinitions(doc, resource);
- }
看下getValidationModeForResource
一路跟踪下来到XmlValidationModeDetector的detectValidationMode方法
- while ((content = reader.readLine()) != null) {
- content = consumeCommentTokens(content);
- if (this.inComment || !StringUtils.hasText(content)) {
- continue;
- }
- if (hasDoctype(content)) {
- isDtdValidated = true;
- break;
- }
- if (hasOpeningTag(content)) {
-
- break;
- }
- }
就是分析下xml文件里有没有DOCTYPE关键字,没有的话就认为是xsd格式的。然后就到了documentLoader.loadDocument(
inputSource, getEntityResolver(), this.errorHandler, validationMode,
isNamespaceAware()); 这个方法
- public Document loadDocument(InputSource inputSource, EntityResolver entityResolver,
- ErrorHandler errorHandler, int validationMode, boolean namespaceAware) throws Exception {
-
- DocumentBuilderFactory factory = createDocumentBuilderFactory(validationMode, namespaceAware);
- if (logger.isDebugEnabled()) {
- logger.debug("Using JAXP provider [" + factory.getClass().getName() + "]");
- }
- DocumentBuilder builder = createDocumentBuilder(factory, entityResolver, errorHandler);
- return builder.parse(inputSource);
- }
其实就是使用DocumentBuilderFactory 去解析xml,这块不怎么熟,查了下网上的介绍也没太详细的。
接着跟踪到registerBeanDefinitions
方法,关键部分:documentReader.registerBeanDefinitions(doc,
createReaderContext(resource));
- public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
- this.readerContext = readerContext;
-
- logger.debug("Loading bean definitions");
- Element root = doc.getDocumentElement();
-
- BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);
-
- preProcessXml(root);
- parseBeanDefinitions(root, delegate);
- postProcessXml(root);
- }
preProcessXml和postProcessXml是提供扩展用得,这里没有具体实现,从字面上理解也是给之类提供预处理和事后处理用
的。具体解析工作是parseBeanDefinitions,跟踪到private void parseDefaultElement(Element ele,
BeanDefinitionParserDelegate delegate)
这个方法,我们主要关注对bean的解析,所以直接看processBeanDefinition(ele, delegate)
-
-
-
-
- protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
-
- BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
- if (bdHolder != null) {
- bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
- try {
-
- BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());
- }
- catch (BeanDefinitionStoreException ex) {
- getReaderContext().error("Failed to register bean definition with name ‘" +
- bdHolder.getBeanName() + "‘", ele, ex);
- }
-
- getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
- }
- }
先
来看delegate.parseBeanDefinitionElement(ele) 方法,BeanDefinitionParserDelegate这个类
里包含了对各种Spring Bean定义规则的处理。比如我们最熟悉 的对Bean元素的处理是怎样完成的,也就是怎样处理在XML定义文件中出现的
<bean></bean>这个最常见的元素信息。在这里会看到对那些熟悉的BeanDefinition定义的处
理,比如id、name、aliase等属性元素。把这些元素的值从XML文件相应的元素的属性中读
取出来以后,设置到生成的BeanDefinitionHolder中去。这些属性的解析还是比较简单的。
对于其他元素配置的解析,比如各种Bean的属性配置,通过一个较为复杂的解析过程,这个
过程是由parseBeanDefinitionElement来完成的。解析完成以后,会把解析结果放到
BeanDefinition对象中并设置到BeanDefinitionHolder中去。其实就是根据spring自己对xml文件的定义进行解析。 这个
BeanDefinition数据对象中封装的数据大多都是与<bean>定义相关的,也有很多就是我们在定义Bean时看到
的那些Spring标记,比如常见的init-method、destroy-method、factory-method,等等,这个
BeanDefinition数据类型是非常重要的,它封装了很多基本数据,这些基本数据都是IoC容器
需要的。有了这些基本数据,IoC容器才能对Bean配置进行处理,才能实现相应的容器特性。spring对资源文件的解析和加载基本到此,下一篇继续分
析spring对bean的获取
贴一张spring 内部调用的图先

spring IoC源码分析 (3)Resource解析,布布扣,bubuko.com
spring IoC源码分析 (3)Resource解析
原文:http://www.cnblogs.com/shisw/p/3641114.html