【Spring Framework 深入】—— IoC容器初始化 -> Bean定义资源的载入解析

来源:互联网 发布:软件过期怎么修改 编辑:程序博客网 时间:2024/05/19 22:25

Bean定义资源的载入解析,Resource是Xml文件的资源描述符(resource descriptor)

回到XmlBeanDefinitionReader的loadBeanDefinitions(Resource …)方法

XmlBeanDefinitionReader.java@Override    public int loadBeanDefinitions(Resource resource) throws BeanDefinitionStoreException {        //将读入的XML资源进行特殊编码处理        return loadBeanDefinitions(new EncodedResource(resource));    }    /**     * Load bean definitions from the specified XML file.     * @param encodedResource the resource descriptor for the XML file,     * allowing to specify an encoding to use for parsing the file     * @return the number of bean definitions found     * @throws BeanDefinitionStoreException in case of loading or parsing errors     */    public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {        ......        try {            //得到资源Resource的IO流            InputStream inputStream = encodedResource.getResource().getInputStream();            try {                //将InputStream包装成InputSource解析流                InputSource inputSource = new InputSource(inputStream);                if (encodedResource.getEncoding() != null) {                    inputSource.setEncoding(encodedResource.getEncoding());                }                //这里是实际处理Resource的过程                return doLoadBeanDefinitions(inputSource, encodedResource.getResource());            }            finally {                inputStream.close();            }        }        ......    }protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)            throws BeanDefinitionStoreException {        try {            //将XML文件转换为DOM对象,解析过程由documentLoader实现            Document doc = doLoadDocument(inputSource, resource);            //启动对Document对象的解析过程            return registerBeanDefinitions(doc, resource);        }        ......    }protected Document doLoadDocument(InputSource inputSource, Resource resource) throws Exception {        //documentLoader将Resource解析成DOM对象并返回        return this.documentLoader.loadDocument(inputSource, getEntityResolver(), this.errorHandler,                getValidationModeForResource(resource), isNamespaceAware());    }

DocumentLoader将Bean定义资源Resource转换成Document对象

DefaultDocumentLoader.java//使用标准的JAXP解析器将载入的Bean定义资源解析成DOM Document实例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);        //解析Bean定义资源        return builder.parse(inputSource);    }

该解析过程调用JavaEE标准的JAXP标准进行处理。
至此Spring IoC容器根据定位的Bean定义资源文件,将其加载读入并转换成为Document对象过程完成。

转换成Document对象后,XmlBeanDefinitionReader委派DefaultBeanDefinitionDocumentReader进行实际的解析工作

XmlBeanDefinitionReader.java//Register the bean definitions contained in the given DOM document.    public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {        BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();        int countBefore = getRegistry().getBeanDefinitionCount();        //BeanDefinitionDocumentReader只是一个接口,        //实际委派给DefaultBeanDefinitionDocumentReader进行解析        documentReader.registerBeanDefinitions(doc, createReaderContext(resource));        return getRegistry().getBeanDefinitionCount() - countBefore;    }    protected BeanDefinitionDocumentReader createBeanDefinitionDocumentReader() {        return BeanDefinitionDocumentReader.class.cast(BeanUtils.instantiateClass(this.documentReaderClass));    }    private Class<?> documentReaderClass = DefaultBeanDefinitionDocumentReader.class;

BeanDefinitionDocumentReader接口通过registerBeanDefinitions方法调用其实现类DefaultBeanDefinitionDocumentReader对Document对象进行解析

DefaultBeanDefinitionDocumentReader.javapublic void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {        this.readerContext = readerContext;        logger.debug("Loading bean definitions");        Element root = doc.getDocumentElement();        doRegisterBeanDefinitions(root);    }protected void doRegisterBeanDefinitions(Element root) {        // 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;        //具体的解析过程由BeanDefinitionParserDelegate实现        //BeanDefinitionParserDelegate中定义了Spring Bean定义XML文件的各种元素        this.delegate = createDelegate(getReaderContext(), root, parent);        if (this.delegate.isDefaultNamespace(root)) {            String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);            if (StringUtils.hasText(profileSpec)) {                String[] specifiedProfiles = StringUtils.tokenizeToStringArray(                        profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);                if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {                    return;                }            }        }        //在解析Bean定义之前,进行自定义的解析,增强解析过程的可扩展性        preProcessXml(root);        //从Document的根元素开始解析Bean定义的Document对象          parseBeanDefinitions(root, this.delegate);        //在解析Bean定义之后,进行自定义的解析,增强解析过程的可扩展性          postProcessXml(root);        this.delegate = parent;    }protected BeanDefinitionParserDelegate createDelegate(            XmlReaderContext readerContext, Element root, BeanDefinitionParserDelegate parentDelegate) {        BeanDefinitionParserDelegate delegate = new BeanDefinitionParserDelegate(readerContext);        delegate.initDefaults(root, parentDelegate);        return delegate;    }

上述的流程图如下:
这里写图片描述

解析过程的核心函数是parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate)

DefaultBeanDefinitionDocumentReader.java//Parse the elements at the root level in the documentprotected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {        //根节点是否使用了Spring默认的XML命名空间        //BeanDefinitionParserDelegate定义了常量,String BEANS_NAMESPACE_URI = "http://www.springframework.org/schema/beans";        if (delegate.isDefaultNamespace(root)) {            NodeList nl = root.getChildNodes();            for (int i = 0; i < nl.getLength(); i++) {                Node node = nl.item(i);                //元素节点是否使用了默认XML命名空间                if (node instanceof Element) {                    Element ele = (Element) node;                    if (delegate.isDefaultNamespace(ele)) {                        //使用Spring的Bean规则解析元素节点                        parseDefaultElement(ele, delegate);                    }                    else {                        //没有使用Spring默认的XML命名空间,则使用用户自定义的解析规则解析元素节点                        delegate.parseCustomElement(ele);                    }                }            }        }        else {            //Document的根节点没有使用Spring默认的命名空间,则使用用户自定义的解析规则解析Document根节点              delegate.parseCustomElement(root);        }    }//使用Spring的Bean规则解析Document元素节点private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {        //元素节点是<Import>        if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {            importBeanDefinitionResource(ele);        }        //元素节点是<Alias>        else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {            processAliasRegistration(ele);        }        //元素节点是<Bean>        else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {            processBeanDefinition(ele, delegate);        }        //元素节点是<Beans>        else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {            // recurse 递归            doRegisterBeanDefinitions(ele);        }    }

<Import><Alias>元素解析在DefaultBeanDefinitionDocumentReader中已经完成,对Bean定义资源文件中使用最多的<Bean>元素交由BeanDefinitionParserDelegate来解析,源码如下

DefaultBeanDefinitionDocumentReader.javaprotected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);        if (bdHolder != null) {            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);            try {                // Register the final decorated instance.                BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());            }            catch (BeanDefinitionStoreException ex) {                getReaderContext().error("Failed to register bean definition with name '" +                        bdHolder.getBeanName() + "'", ele, ex);            }            // Send registration event.            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));        }    }
BeanDefinitionParserDelegate.java//解析<Bean>元素的入口public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {        return parseBeanDefinitionElement(ele, null);    }//解析Bean定义资源文件中的<Bean>元素,这个方法中主要处理<Bean>元素的id,name和别名属性 public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) //详细对<Bean>元素中配置的Bean定义其他属性进行解析,除id,name和别名属性三个以外的其他属性数据  public AbstractBeanDefinition parseBeanDefinitionElement(            Element ele, String beanName, BeanDefinition containingBean)

注意,在上述解析过程中,只是根据元素的配置信息创建了相应的定义类BeanDefinition,没有创建和实例化Bean对象,依赖注入才会使用这些记录信息创建和实例化具体的Bean对象

<Bean>常用的属性配置:id、name、alias和property

篇幅较大。。。留到以后再详细学习。

向IoC容器注册BeanDefinition

通过Spring IoC容器对Bean定义资源的解析后,IoC容器大致完成了管理Bean对象的准备工作,即初始化过程,但是最为重要的依赖注入还没有发生,现在在IoC容器中BeanDefinition存储的只是一些静态信息,接下来需要向容器注册Bean定义信息才能全部完成IoC容器的初始化过程。
回到DefaultBeanDefinitionDocumentReader的processBeanDefinition函数,BeanDefinitionParserDelegate 的BeanDefinitionParserDelegate 函数完成后,返回封装BeanDefinition的BeanDefinitionHold对象,接下来,调用BeanDefinitionReaderUtils的registerBeanDefinition方法向IoC容器注册解析的Bean。
函数调用流程图:
这里写图片描述

DefaultBeanDefinitionDocumentReader.javaprotected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);        if (bdHolder != null) {            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);            try {                // Register the final decorated instance.                //向容器注册BeanDefinition的入口                      BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());            }            catch (BeanDefinitionStoreException ex) {                getReaderContext().error("Failed to register bean definition with name '" +                        bdHolder.getBeanName() + "'", ele, ex);            }            // Send registration event.            //注册完成后,发送注册事件            getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));        }    }

待续。。。

0 0
原创粉丝点击