6-spring源码3.2.18解读+spring技术内幕(关于BeanDefinition的载入和解析)

1、导读

在完成对代表BeanDefinitionResource定位的分析后,下面来了解整个BeanDefinition信息的载入过程。对Ioc容器来说。这个载入过程相当于把定义的BeanDefinitionIOC容器中转化成一个Spring内部表示的数据结构。IOC容器对Bean的管理和依赖注入功能的实现,是通过对其持有的BeanDefinition进行各种相关操作来完成的。这些BeanDefinition数据在IOC容器中通过一个HashMap来保持维护。当然这只是一种比较简单的维护方式,如果需要提高IOC容器的性能和容量,完全可以自己做一些扩展。接下来我们将结合上一篇文章的流程图继续进行描述。

2BeanDefinition的载入和解析流程图

 6-spring源码3.2.18解读+spring技术内幕(关于BeanDefinition的载入和解析)

 

总的来说,ApplicationContext将解析配置文件的工作委托给AbstractBeanDefinitionReader的子类XmlBeanDefinitionReader,同时调用AbstractBeanDefinitionReader类中的一系列loandBeanDefinitions()方法获取BeanDefinitionResource表示并传递给XmlBeanDefinitionReader,然后AbstractBeanDefinitionReader的子类XmlBeanDefinitionReader将配置文件读取为xmlDocument文档之后,又委托给BeanDefinitionDocumentReaderBeanDefinitionDocumentReader的子类DefaultBeanDefinitionDocumentReader这个组件是根据xml元素的命名空间和元素名,起到一个路由的作用,实际的解析工作,是委托给BeanDefinitionParserDelegate来完成的 

BeanDefinitionParserDelegate的解析工作完成以后,会返回BeanDefinitionHolderDefaultBeanDefinitionDocumentReader,这里BeanDefinition的载入和解析已经完成。(之后,会委托给DefaultListableBeanFactory完成bean的注册 )。

上图大致上描述了一个主要的调用流程,下面我们将进行详细的描述。

 

3、具体调用过程

结合红黑联盟的一张类图结构及调用关系我们将对资源的载入和解析进行深入的研究。

 6-spring源码3.2.18解读+spring技术内幕(关于BeanDefinition的载入和解析)

3.1AbstractBeanDefinitionReader

首先,AbstractXmlApplicationContext会生成一个XmlBeanDefinitionReader对象,并调用该对象的父类中的实现方法loadBeanDefinitions(String... locations)。在AbstractBeanDefinitionReader类中,首先调用loadBeanDefinitions(String... locations)方法,在该方法中循环遍历localtions对每一个location调用loadBeanDefinitions(String location),接着loadBeanDefinitions(String location)调用本类中的loadBeanDefinitions(String location, Set<Resource> actualResources),在这个方法中将会调用ResourcePatternResolver类中的方法定位到资源的具体的位置并返回一个Resource,同时调用该类的子类XmlBeanDefinitionReaderloadBeanDefinitions(Resource var1)方法进入到下一步对资源载入和注册。(字体调用顺序:红--》黄--》蓝,进入下一个流程:全红)

 

 

public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {
    return this.loadBeanDefinitions(location, (Set)null);
}

public int loadBeanDefinitions(String location, Set<Resource> actualResources) throws BeanDefinitionStoreException {
    ResourceLoader resourceLoader = this.getResourceLoader();
    if(resourceLoader == null) {
        throw new BeanDefinitionStoreException("Cannot import bean definitions from location [" + location + "]: no ResourceLoader available");
    } else {
        int loadCount;
        if(!(resourceLoader instanceof ResourcePatternResolver)) {
            Resource var11 = resourceLoader.getResource(location);
            loadCount = this.loadBeanDefinitions((Resource)var11);
            if(actualResources != null) {
                actualResources.add(var11);
            }

            if(this.logger.isDebugEnabled()) {
                this.logger.debug("Loaded " + loadCount + " bean definitions from location [" + location + "]");
            }

            return loadCount;
        } else {
            try {
                Resource[] resource = ((ResourcePatternResolver)resourceLoader).getResources(location);
                loadCount = this.loadBeanDefinitions((Resource[])resource);
                if(actualResources != null) {
                    Resource[] arr$ = resource;
                    int len$ = resource.length;

                    for(int i$ = 0; i$ < len$; ++i$) {
                        Resource resource1 = arr$[i$];
                        actualResources.add(resource1);
                    }
                }

                if(this.logger.isDebugEnabled()) {
                    this.logger.debug("Loaded " + loadCount + " bean definitions from location pattern [" + location + "]");
                }

                return loadCount;
            } catch (IOException var10) {
                throw new BeanDefinitionStoreException("Could not resolve bean definition resource pattern [" + location + "]", var10);
            }
        }
    }
}

public int loadBeanDefinitions(String... locations) throws BeanDefinitionStoreException {
    Assert.notNull(locations, "Location array must not be null");
    int counter = 0;
    String[] arr$ = locations;
    int len$ = locations.length;

    for(int i$ = 0; i$ < len$; ++i$) {
        String location = arr$[i$];
        counter += this.loadBeanDefinitions((String)location);
    }

    return counter;
}

 

3.2XmlBeanDefinitionReader

XmlBeanDefinitionReader中,进入到loadBeanDefinitions(Resource resource)方法中,该方法将继续调用本类中的loadBeanDefinitions(EncodedResource encodedResource) 方法,loadBeanDefinitions(EncodedResource encodedResource) 先获取资源的输入流,然后再加载该方法中的this.doLoadBeanDefinitions(inputSource, encodedResource.getResource())方法,this.doLoadBeanDefinitions(inputSource, encodedResource.getResource())先是获取以Document文档形式的资源,然后再调用本类中的this.registerBeanDefinitions(doc, resource);

this.registerBeanDefinitions(doc, resource);this.registerBeanDefinitions(doc, resource);方法中将会创建一个BeanDefinitionDocumentReader 对象,并调用该类的子类的实现方法documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));进行下一步操作。

 

 

public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {
    return this.loadBeanDefinitions((EncodedResource)(new EncodedResource(resource)));
}

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {
//这里得到XML文件,并得到IOInputSource准备进行读取
     InputStream ex = encodedResource.getResource().getInputStream();
     var5 = this.doLoadBeanDefinitions(inputSource, encodedResource.getResource());
     return var5;
    }
}

//具体的读取过程可以在doLoadBeanDefiniitons方法中找到

//这里是从特定的XML文件中实际载入BeanDefinition的地方

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource) throws BeanDefinitionStoreException {
        int ex = this.getValidationModeForResource(resource);

//这里取得的XML文件的Document对象,这个解析过程是有documentLoader完成的,documentLoaderDefaultDocumentLoader,在定义documentLoader的地方创建
        Document doc = this.documentLoader.loadDocument(inputSource, this.getEntityResolver(), this.errorHandler, ex, this.isNamespaceAware());

//这里启动的是对BeanDefinition解析的详细过程,这个解析会使用到SpringBean配置规则,是需要详细讲解的内容。
        return this.registerBeanDefinitions(doc, resource);
   }

 

//Spring中,BeanDefinition是怎样按照SpringBean语义要求进行解析并转化为容器内部数据结构,这个过程是在registerBeanDefinitions(doc,resource)中完成的,具体的过程是由BeanDefinitionDocumentReader来完成的,并且还对载入的Bean数量进行统计。具体代码如下

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {

//这里得到BeanDefinitionDocumentReader来对XMLBeanDefinition进行解析
    BeanDefinitionDocumentReader documentReader = this.createBeanDefinitionDocumentReader();
    documentReader.setEnvironment(this.getEnvironment());
    int countBefore = this.getRegistry().getBeanDefinitionCount();
//具体的计息过程在这个registerBeanDefinitions中完成

    documentReader.registerBeanDefinitions(doc, this.createReaderContext(resource));
    return this.getRegistry().getBeanDefinitionCount() - countBefore;
}

 

 

3.3DefaultBeanDefinitionDocumentReader

BeanDefinitionDocumentReader的实现类DefaultBeanDefinitionDocumentReaderregisterBeanDefinitions方法,在该方法中将会获取以Element形式存在的bean文件的信息,然后传递给doRegisterBeanDefinitions(Element root)方法进行调用,在doRegisterBeanDefinitions(Element root)中,实例化一个BeanDefinitionParserDelegate 类的对象并传递给 this.parseBeanDefinitions(root, this.delegate);方法进行下一步操作,在 parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) 方法中,以root为根节点对象将会进行进一步的遍历得到element元素并传递给parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 进行下一步的解析。在parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) 方法中将会根据节点的名字不同调用不同的解析方法,这里将会调用processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) bean命名的元素进行解析,在processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) 将会进一步调用delegate.parseBeanDefinitionElement(ele);方法对bean元素进行解析,并返回一个BeanDefinitionHolder对象保存bean元素的所包含信息,对于parseBeanDefinitionElement()方法的具体实现则是在BeanDefinitionParserDelegate类中。

 

 

 

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
    this.readerContext = readerContext;
    this.logger.debug("Loading bean definitions");
    Element root = doc.getDocumentElement();
    this.doRegisterBeanDefinitions(root);
}

 

protected void doRegisterBeanDefinitions(Element root) {
    String profileSpec = root.getAttribute("profile");
    if(StringUtils.hasText(profileSpec)) {
        String[] parent = StringUtils.tokenizeToStringArray(profileSpec, ",; ");
        if(!this.getEnvironment().acceptsProfiles(parent)) {
            return;
        }
    }

    BeanDefinitionParserDelegate parent1 = this.delegate;
    this.delegate = this.createDelegate(this.readerContext, root, parent1);
    this.preProcessXml(root);
    this.parseBeanDefinitions(root, this.delegate);
    this.postProcessXml(root);
    this.delegate = parent1;
}

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);
    }

}

 

 

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);
    }

}

 

 

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
    BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
    if(bdHolder != null) {
        bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

        try {
            BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());
        } catch (BeanDefinitionStoreException var5) {
            this.getReaderContext().error("Failed to register bean definition with name \'" + bdHolder.getBeanName() + "\'", ele, var5);
        }

        this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
    }

}

 

3.4BeanDefinitionParserDelegate

BeanDefinitionParserDelegate类中parseBeanDefinitionElement(ele)方法将会被调用,在该类中经过一系列的调用最后将会decorateBeanDefinitionIfRequired()方法对BeanDefinition进行解析。同时返回BeandDefinitionHolder给下一步注册。

 

 

public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {
    BeanDefinitionHolder finalDefinition = definitionHolder;
    NamedNodeMap attributes = ele.getAttributes();

    for(int children = 0; children < attributes.getLength(); ++children) {
        Node i = attributes.item(children);
        finalDefinition = this.decorateIfRequired(i, finalDefinition, containingBd);
    }

    NodeList var9 = ele.getChildNodes();

    for(int var10 = 0; var10 < var9.getLength(); ++var10) {
        Node node = var9.item(var10);
        if(node.getNodeType() == 1) {
            finalDefinition = this.decorateIfRequired(node, finalDefinition, containingBd);
        }
    }

    return finalDefinition;
}