美文网首页
Spring XML解析的详细过程 1

Spring XML解析的详细过程 1

作者: 农民工进城 | 来源:发表于2019-09-26 12:08 被阅读0次

    本章要点

    • XML默认节点的解析过程

    1. 默认节点的解析过程

    代码片段:

            <bean id="mybean" name="yourbean,herbean"
            class="com.ailk.service.MyBean">
            <lookup-method name="say" bean="lookUp" />
            <replaced-method name="say" replacer="myReplaced" />
            <meta key="name" value="zhaosc" />
            <constructor-arg></constructor-arg>
            <property name=""></property>
            <qualifier></qualifier>
        </bean>
        <bean id="lookUp" class="com.ailk.service.LookupBean"></bean>
        <bean id="myReplaced" class="com.ailk.service.MyReplaced"></bean>
        <alias name="yourbean" alias="one"></alias>
    
    public class MyReplaced implements MethodReplacer {
        public Object reimplement(Object obj, Method method, Object[] args) throws Throwable {
            System.out.println("*****MyReplaced*****");
            return null;
        }
    }
    
    public class LookupBean {
        public LookupBean() {
            super();
            System.out.println("*****实例化*****");
        }
        public void lookup(){
            System.out.println("*****lookup*****");
        }
    }
    
    public class MyBean {
        public void say(){
            System.out.println("*****hello*****");
        }
    
    }
    

    默认节点主要包括import、alias、bean、beans 四类:
    org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.parseDefaultElement(Element, BeanDefinitionParserDelegate)

        private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) {
            if (delegate.nodeNameEquals(ele, IMPORT_ELEMENT)) {
                importBeanDefinitionResource(ele);//1)
            }
            else if (delegate.nodeNameEquals(ele, ALIAS_ELEMENT)) {
                processAliasRegistration(ele);//2)
            }
            else if (delegate.nodeNameEquals(ele, BEAN_ELEMENT)) {
                processBeanDefinition(ele, delegate);//3)
            }
            else if (delegate.nodeNameEquals(ele, NESTED_BEANS_ELEMENT)) {
                // recurse
                doRegisterBeanDefinitions(ele);//4)
            }
        }
    

    1)解析import节点
    2)解析alias节点
    3)解析bean节点
    4)解析beans节点

    1.1 解析import标签

    org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource(Element)

    protected void importBeanDefinitionResource(Element ele) {
            String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
            if (!StringUtils.hasText(location)) {
                getReaderContext().error("Resource location must not be empty", ele);
                return;
            }
            location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);
    
            Set<Resource> actualResources = new LinkedHashSet<>(4);
    
            // Discover whether the location is an absolute or relative URI
            boolean absoluteLocation = false;
            try {
                absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
            }
            catch (URISyntaxException ex) {
                // cannot convert to an URI, considering the location relative
                // unless it is the well-known Spring prefix "classpath*:"
            }
    
            // Absolute or relative?
            if (absoluteLocation) {
                try {
                    int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources); //1)
                    if (logger.isDebugEnabled()) {
                        logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
                    }
                }
                catch (BeanDefinitionStoreException ex) {
                    getReaderContext().error(
                            "Failed to import bean definitions from URL location [" + location + "]", ele, ex);
                }
            }
            else {
                // No URL -> considering resource location as relative to the current file.
                try {
                    int importCount;
                    Resource relativeResource = getReaderContext().getResource().createRelative(location);
                    if (relativeResource.exists()) {
                        importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
                        actualResources.add(relativeResource);
                    }
                    else {
                        String baseLocation = getReaderContext().getResource().getURL().toString();
                        importCount = getReaderContext().getReader().loadBeanDefinitions(
                                StringUtils.applyRelativePath(baseLocation, location), actualResources);
                    }
                    if (logger.isDebugEnabled()) {
                        logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
                    }
                }
                catch (IOException ex) {
                    getReaderContext().error("Failed to resolve current resource location", ele, ex);
                }
                catch (BeanDefinitionStoreException ex) {
                    getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]",
                            ele, ex);
                }
            }
            Resource[] actResArray = actualResources.toArray(new Resource[0]);
            getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
        }
    
    
    • 1)比较简单解析标签,获取路径,进行加载读取文件
    1.2 解析alias标签

    org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processAliasRegistration(Element)

    protected void processAliasRegistration(Element ele) {
            String name = ele.getAttribute(NAME_ATTRIBUTE);
            String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
            boolean valid = true;
            if (!StringUtils.hasText(name)) {
                getReaderContext().error("Name must not be empty", ele);
                valid = false;
            }
            if (!StringUtils.hasText(alias)) {
                getReaderContext().error("Alias must not be empty", ele);
                valid = false;
            }
            if (valid) {
                try {
                    getReaderContext().getRegistry().registerAlias(name, alias);//1)注册
                }
                catch (Exception ex) {
                    getReaderContext().error("Failed to register alias '" + alias +
                            "' for bean with name '" + name + "'", ele, ex);
                }
                getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
            }
        }
    
    • 1)解析alias标签,注册到org.springframework.core.SimpleAliasRegistry.aliasMap
    1.3解析bena标签(重点

    org.springframework.beans.factory.xml.DefaultBeanDefinitionDocumentReader.processBeanDefinition(Element, BeanDefinitionParserDelegate)

    protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
            BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);//1)
            if (bdHolder != null) {
                bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);
                try {
                    // Register the final decorated instance.
                    BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());//2)
                }
                catch (BeanDefinitionStoreException ex) {
                    getReaderContext().error("Failed to register bean definition with name '" +
                            bdHolder.getBeanName() + "'", ele, ex);
                }
                // Send registration event.
                getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
            }
        }
    
    
    • 1)解析bean标签,并形成BeanDefinition,封装为BeanDefinitionHolder
    • 2)将BeanDefinition注册到org.springframework.beans.factory.support.DefaultListableBeanFactory.beanDefinitionMap
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele) {
            return parseBeanDefinitionElement(ele, null);
        }
    
    public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, @Nullable BeanDefinition containingBean) {
            String id = ele.getAttribute(ID_ATTRIBUTE);//1)
            String nameAttr = ele.getAttribute(NAME_ATTRIBUTE);//2)
    
            List<String> aliases = new ArrayList<>();
            if (StringUtils.hasLength(nameAttr)) {
                String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, MULTI_VALUE_ATTRIBUTE_DELIMITERS);//3)
                aliases.addAll(Arrays.asList(nameArr));
            }
    
            String beanName = id;
            if (!StringUtils.hasText(beanName) && !aliases.isEmpty()) {
                beanName = aliases.remove(0);
                if (logger.isDebugEnabled()) {
                    logger.debug("No XML 'id' specified - using '" + beanName +
                            "' as bean name and " + aliases + " as aliases");
                }
            }
    
            if (containingBean == null) {
                checkNameUniqueness(beanName, aliases, ele);//4)
            }
    
            AbstractBeanDefinition beanDefinition = parseBeanDefinitionElement(ele, beanName, containingBean);//5)
            if (beanDefinition != null) {
                if (!StringUtils.hasText(beanName)) {
                    try {
                        if (containingBean != null) {
                            beanName = BeanDefinitionReaderUtils.generateBeanName(
                                    beanDefinition, this.readerContext.getRegistry(), true);
                        }
                        else {
                            beanName = this.readerContext.generateBeanName(beanDefinition);
                            
                            String beanClassName = beanDefinition.getBeanClassName();
                            if (beanClassName != null &&
                                    beanName.startsWith(beanClassName) && beanName.length() > beanClassName.length() &&
                                    !this.readerContext.getRegistry().isBeanNameInUse(beanClassName)) {
                                aliases.add(beanClassName);
                            }
                        }
                        if (logger.isDebugEnabled()) {
                            logger.debug("Neither XML 'id' nor 'name' specified - " +
                                    "using generated bean name [" + beanName + "]");
                        }
                    }
                    catch (Exception ex) {
                        error(ex.getMessage(), ele);
                        return null;
                    }
                }
                String[] aliasesArray = StringUtils.toStringArray(aliases);
                return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
            }
    
            return null;
        }
    
      1. 获取bean标签的id属性
    • 2)获取bean标签的name属性
    • 3)name如果配置了多个别名,需要按逗号“,”或分号“;”分开
    • 4)检查beanname是否唯一(usedNames中是否已经含有该name),唯一则将名字放进
      org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.usedNames Map 中
    • 5)解析bean标签,封装成BeanDefinition对象

    下面看下详细的解析过程
    org.springframework.beans.factory.xml.BeanDefinitionParserDelegate.parseBeanDefinitionElement(Element, String, BeanDefinition)

    public AbstractBeanDefinition parseBeanDefinitionElement(
                Element ele, String beanName, @Nullable BeanDefinition containingBean) {
    
            this.parseState.push(new BeanEntry(beanName));//1)将正在进行操作的bean放在链表中
    
            String className = null;
            if (ele.hasAttribute(CLASS_ATTRIBUTE)) {
                className = ele.getAttribute(CLASS_ATTRIBUTE).trim();
            }
            String parent = null;
            if (ele.hasAttribute(PARENT_ATTRIBUTE)) {
                parent = ele.getAttribute(PARENT_ATTRIBUTE);
            }
    
            try {
                AbstractBeanDefinition bd = createBeanDefinition(className, parent);//2)创建GenericBeanDefinition对象,并设置BeanClassName和BeanClass属性
    
                parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);//3)解析bean标签属性
                bd.setDescription(DomUtils.getChildElementValueByTagName(ele, DESCRIPTION_ELEMENT));
    
                parseMetaElements(ele, bd);//4)解析meta子标签
                parseLookupOverrideSubElements(ele, bd.getMethodOverrides());//5)
                parseReplacedMethodSubElements(ele, bd.getMethodOverrides());//6)
    
                parseConstructorArgElements(ele, bd);//7)
                parsePropertyElements(ele, bd);//8)
                parseQualifierElements(ele, bd);//9)
    
                bd.setResource(this.readerContext.getResource());
                bd.setSource(extractSource(ele));
    
                return bd;
            }
            catch (ClassNotFoundException ex) {
                error("Bean class [" + className + "] not found", ele, ex);
            }
            catch (NoClassDefFoundError err) {
                error("Class that bean class [" + className + "] depends on not found", ele, err);
            }
            catch (Throwable ex) {
                error("Unexpected failure during bean definition parsing", ele, ex);
            }
            finally {
                this.parseState.pop();//10)
            }
    
            return null;
        }
    
    
    • 1)将正在进行操作的bean放在parseState链表中
    • 2)创建GenericBeanDefinition对象,并设置BeanClassName和BeanClass属性
    • 3)解析bean标签的scope、abstract、lazy-init、autowire、init-method、destroy-method、factory-method、factory-bean各种属性,封装成BeanDefinition对象,设置成BeanDefinition对象的属性值
    • 4)解析meta子标签
    • 5)解析lookup-method子标签
    • 6)解析replaced-method子标签
    • 7)解析constructor-arg子标签
    • 8)解析property子标签
    • 9)解析qualifier子标签
    • 10)已完成bean解析,则弹出parseState链表

    相关文章

      网友评论

          本文标题:Spring XML解析的详细过程 1

          本文链接:https://www.haomeiwen.com/subject/vuweyctx.html