Spring源码解析-默认标签的解析

Spirng的xml配置中有两大类标签

一种是默认的:如
<bean id="" class=""/>
另一种是自定义的:如
<tx:annotion-driven>

进入parseDefaultElement()方法,可见分别对四种默认标签进行了处理(import,alias,bean,beans)。

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

    }

bean标签的解析与注册

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

    }

首先进行元素的解析,进入parseBeanDefinitionElement()方法,

public BeanDefinitionHolder parseBeanDefinitionElement(Element ele, BeanDefinition containingBean) {
        //解析id属性
        String id = ele.getAttribute("id");
        //解析name属性
        String nameAttr = ele.getAttribute("name");
        //分割name属性
        List<String> aliases = new ArrayList();
        if(StringUtils.hasLength(nameAttr)) {
            String[] nameArr = StringUtils.tokenizeToStringArray(nameAttr, ",; ");
            aliases.addAll(Arrays.asList(nameArr));
        }

        String beanName = id;
        //如果id不存在且别名集合不为空,那么把集合的第一个别名当作beanName
        if(!StringUtils.hasText(id) && !aliases.isEmpty()) {
            beanName = (String)aliases.remove(0);
            if(this.logger.isDebugEnabled()) {
                this.logger.debug("No XML 'id' specified - using '" + beanName + "' as bean name and " + aliases + " as aliases");
            }
        }

        if(containingBean == null) {
            this.checkNameUniqueness(beanName, aliases, ele);
        }
        //进一步解析其他所有属性并封装
        AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
        if(beanDefinition != null) {
            //如果beanName不存在 那么根据spring提供的命名规则生成beanName
            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(this.logger.isDebugEnabled()) {
                        this.logger.debug("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
                    }
                } catch (Exception var9) {
                    this.error(var9.getMessage(), ele);
                    return null;
                }
            }

            String[] aliasesArray = StringUtils.toStringArray(aliases);
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        } else {
            return null;
        }
    }

我们进入
AbstractBeanDefinition beanDefinition = this.parseBeanDefinitionElement(ele, beanName, containingBean);
方法查看,这个方法对标签其他属性进行解析

public AbstractBeanDefinition parseBeanDefinitionElement(Element ele, String beanName, BeanDefinition containingBean) {
        this.parseState.push(new BeanEntry(beanName));
        String className = null;
        //解析class属性
        if(ele.hasAttribute("class")) {
            className = ele.getAttribute("class").trim();
        }

        try {
            String parent = null;
            //解析parent属性
            if(ele.hasAttribute("parent")) {
                parent = ele.getAttribute("parent");
            }
            //创建承载属性的AbstractBeanDefinition,实际类型是GenericBeanDefinition
            AbstractBeanDefinition bd = this.createBeanDefinition(className, parent);
            //接着解析bean的各种属性
            this.parseBeanDefinitionAttributes(ele, beanName, containingBean, bd);

接着,我们进入这个parseBeanDefinitionAttributes方法,我们可以很清楚的看到这里解析了什么属性,这里就不一一解释了。

public AbstractBeanDefinition parseBeanDefinitionAttributes(Element ele, String beanName, BeanDefinition containingBean, AbstractBeanDefinition bd) {
        if(ele.hasAttribute("scope")) {
            bd.setScope(ele.getAttribute("scope"));
        } else if(containingBean != null) {
            bd.setScope(containingBean.getScope());
        }

        if(ele.hasAttribute("abstract")) {
            bd.setAbstract("true".equals(ele.getAttribute("abstract")));
        }

        String lazyInit = ele.getAttribute("lazy-init");
        if("default".equals(lazyInit)) {
            lazyInit = this.defaults.getLazyInit();
        }

        bd.setLazyInit("true".equals(lazyInit));
        String autowire = ele.getAttribute("autowire");
        bd.setAutowireMode(this.getAutowireMode(autowire));
        String dependencyCheck = ele.getAttribute("dependency-check");
        bd.setDependencyCheck(this.getDependencyCheck(dependencyCheck));
        String autowireCandidate;
        if(ele.hasAttribute("depends-on")) {
            autowireCandidate = ele.getAttribute("depends-on");
            bd.setDependsOn(StringUtils.tokenizeToStringArray(autowireCandidate, ",; "));
        }

        autowireCandidate = ele.getAttribute("autowire-candidate");
        String destroyMethodName;
        if(!"".equals(autowireCandidate) && !"default".equals(autowireCandidate)) {
            bd.setAutowireCandidate("true".equals(autowireCandidate));
        } else {
            destroyMethodName = this.defaults.getAutowireCandidates();
            if(destroyMethodName != null) {
                String[] patterns = StringUtils.commaDelimitedListToStringArray(destroyMethodName);
                bd.setAutowireCandidate(PatternMatchUtils.simpleMatch(patterns, beanName));
            }
        }

        if(ele.hasAttribute("primary")) {
            bd.setPrimary("true".equals(ele.getAttribute("primary")));
        }

        if(ele.hasAttribute("init-method")) {
            destroyMethodName = ele.getAttribute("init-method");
            if(!"".equals(destroyMethodName)) {
                bd.setInitMethodName(destroyMethodName);
            }
        } else if(this.defaults.getInitMethod() != null) {
            bd.setInitMethodName(this.defaults.getInitMethod());
            bd.setEnforceInitMethod(false);
        }

        if(ele.hasAttribute("destroy-method")) {
            destroyMethodName = ele.getAttribute("destroy-method");
            if(!"".equals(destroyMethodName)) {
                bd.setDestroyMethodName(destroyMethodName);
            }
        } else if(this.defaults.getDestroyMethod() != null) {
            bd.setDestroyMethodName(this.defaults.getDestroyMethod());
            bd.setEnforceDestroyMethod(false);
        }

        if(ele.hasAttribute("factory-method")) {
            bd.setFactoryMethodName(ele.getAttribute("factory-method"));
        }

        if(ele.hasAttribute("factory-bean")) {
            bd.setFactoryBeanName(ele.getAttribute("factory-bean"));
        }

        return bd;
    }

接着看之前的代码

//提取描述到bd
bd.setDescription(DomUtils.getChildElementValueByTagName(ele, "description"));
//解析元数据
            this.parseMetaElements(ele, bd);

进入这个方法查看,元数据就是bean标签下的meta标签,这个标签包含两个属性,一个是key,一个是value。元数据相当于给类中对应的属性赋值。

<bean id="" class="">
    <meta key="属性" value="值">
</bean>
public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) {
//获取所有子节点
        NodeList nl = ele.getChildNodes();
    //遍历子节点,装配元数据,将元数据属性添加到原来的bd中
        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            if(this.isCandidateElement(node) && this.nodeNameEquals(node, "meta")) {
                Element metaElement = (Element)node;
                String key = metaElement.getAttribute("key");
                String value = metaElement.getAttribute("value");
                BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value);
                attribute.setSource(this.extractSource(metaElement));
                attributeAccessor.addMetadataAttribute(attribute);
            }
        }

    }

接着来看

//解析look-method属性
            this.parseLookupOverrideSubElements(ele, bd.getMethodOverrides());

进入方法,look-method属性并不常用,能实现依赖的注入,或者说对象的插拔

<bean id="" class="">
    <lookup-method name="这个类中的方法名,这方法能返回一个实例对象" bean="这个实例对象的bean的名称">
</bean>
public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) {
        NodeList nl = beanEle.getChildNodes();

        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            if(this.isCandidateElement(node) && this.nodeNameEquals(node, "lookup-method")) {
                Element ele = (Element)node;
                //获取需要修饰的方法
                String methodName = ele.getAttribute("name");
                //获取配置的bean
                String beanRef = ele.getAttribute("bean");
                LookupOverride override = new LookupOverride(methodName, beanRef);
                override.setSource(this.extractSource(ele));
                添加到bd的MethodOverrides中
                overrides.addOverride(override);
            }
        }

    }

接着来看解析replaced-method属性

            this.parseReplacedMethodSubElements(ele, bd.getMethodOverrides());

怎么用

<bean id="" class="">
    <replaced-method name="该类中需要被重写或者说替换的方法名" replacer="进行替换的bean名称,这个类需要实现MethodReplacer方法">
</bean>
结果是替换类的方法会替换原来类的方法,实现的MethodReplacer的方法跟动态代理很像,所以我们可以猜想到这个方法替换是怎么实现的。

接着看这个标签解析

public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) {
        NodeList nl = beanEle.getChildNodes();

        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            if(this.isCandidateElement(node) && this.nodeNameEquals(node, "replaced-method")) {
                Element replacedMethodEle = (Element)node;
                //获取旧方法名
                String name = replacedMethodEle.getAttribute("name");
                //新的替换方法
                String callback = replacedMethodEle.getAttribute("replacer");
                ReplaceOverride replaceOverride = new ReplaceOverride(name, callback);
                List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, "arg-type");
                Iterator var11 = argTypeEles.iterator();

                while(var11.hasNext()) {
                    Element argTypeEle = (Element)var11.next();
                    String match = argTypeEle.getAttribute("match");
                    match = StringUtils.hasText(match)?match:DomUtils.getTextValue(argTypeEle);
                    if(StringUtils.hasText(match)) {
                        replaceOverride.addTypeIdentifier(match);
                    }
                }

                replaceOverride.setSource(this.extractSource(replacedMethodEle));
                //最后还是添加到bd的MethodOverrides中
                overrides.addOverride(replaceOverride);
            }
        }

    }

接着来看解析构造函数参数

            this.parseConstructorArgElements(ele, bd);
public void parseConstructorArgElements(Element beanEle, BeanDefinition bd) {
        NodeList nl = beanEle.getChildNodes();

        for(int i = 0; i < nl.getLength(); ++i) {
            Node node = nl.item(i);
            if(this.isCandidateElement(node) && this.nodeNameEquals(node, "constructor-arg")) {
                this.parseConstructorArgElement((Element)node, bd);
            }
        }

    }
            //解析子元素property 
            this.parsePropertyElements(ele, bd);
            //解析子元素qualifier
            this.parseQualifierElements(ele, bd);
            bd.setResource(this.readerContext.getResource());
            bd.setSource(this.extractSource(ele));
            AbstractBeanDefinition var7 = bd;
            return var7;
        } catch (ClassNotFoundException var13) {
            this.error("Bean class [" + className + "] not found", ele, var13);
        } catch (NoClassDefFoundError var14) {
            this.error("Class that bean class [" + className + "] depends on not found", ele, var14);
        } catch (Throwable var15) {
            this.error("Unexpected failure during bean definition parsing", ele, var15);
        } finally {
            this.parseState.pop();
        }

        return null;
    }

然后我们就得到了这个承载bean所有属性的GenericBeanDefinition,回到原来的解析bean的方法parseBeanDefinitionElement,我们可以看到接下来是如果没有检测到beanName,然后生成默认的beanName,然后将所有获取到的信息封装进BeanDefinitionHolder,最后返回。

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(this.logger.isDebugEnabled()) {
                        this.logger.debug("Neither XML 'id' nor 'name' specified - using generated bean name [" + beanName + "]");
                    }
                } catch (Exception var9) {
                    this.error(var9.getMessage(), ele);
                    return null;
                }
            }

            String[] aliasesArray = StringUtils.toStringArray(aliases);
            //将所有获取到的信息封装进BeanDefinitionHolder,然后返回
            return new BeanDefinitionHolder(beanDefinition, beanName, aliasesArray);
        } else {
            return null;
        }

接着回到之前的processBeanDefinition方法,此时已经获取了BeanDefinitionHolder ,

protected void processBeanDefinition(Element ele, BeanDefinitionParserDelegate delegate) {
        //解析元素封装进BeanDefinitionHolder
        BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);
        if(bdHolder != null) {
            //如果存在自定义标签,继续解析
            bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

接着我们来看对自定义标签的解析,可是这个默认标签中的怎么会存在自定义类型的解析呢,其实之前说的默认和自定义是针对于Bean,而这里的自定义类型其实是属性。

public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder) {
        return this.decorateBeanDefinitionIfRequired(ele, definitionHolder, (BeanDefinition)null);
    }

    public BeanDefinitionHolder decorateBeanDefinitionIfRequired(Element ele, BeanDefinitionHolder definitionHolder, BeanDefinition containingBd) {
        BeanDefinitionHolder finalDefinition = definitionHolder;
        NamedNodeMap attributes = ele.getAttributes();
        //遍历所有属性,看看是否有用于修饰的属性
        for(int i = 0; i < attributes.getLength(); ++i) {
            Node node = attributes.item(i);
            finalDefinition = this.decorateIfRequired(node, finalDefinition, containingBd);
        }

        NodeList children = ele.getChildNodes();
        //遍历所有子节点,看看是否有需要修饰的子元素
        for(int i = 0; i < children.getLength(); ++i) {
            Node node = children.item(i);
            if(node.getNodeType() == 1) {
                finalDefinition = this.decorateIfRequired(node, finalDefinition, containingBd);
            }
        }

        return finalDefinition;
    }

进入decorateIfRequired()方法

public BeanDefinitionHolder decorateIfRequired(Node node, BeanDefinitionHolder originalDef, BeanDefinition containingBd) {
        //获取自定义标签的命名空间
        String namespaceUri = this.getNamespaceURI(node);
        //对非默认标签进行修饰
        if(!this.isDefaultNamespace(namespaceUri)) {
        //根据命名空间找到对应处理器
            NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
            if(handler != null) {
                //对元素进行修饰
                return handler.decorate(node, originalDef, new ParserContext(this.readerContext, this, containingBd));
            }

            if(namespaceUri != null && namespaceUri.startsWith("http://www.springframework.org/")) {
                this.error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", node);
            } else if(this.logger.isDebugEnabled()) {
                this.logger.debug("No Spring NamespaceHandler found for XML schema namespace [" + namespaceUri + "]");
            }
        }

        return originalDef;
    }

然后我们要注解已经解析完的BeanDefinition

            try {
              //将beanHolder进行注册 BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, this.getReaderContext().getRegistry());

进入方法

public static void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) throws BeanDefinitionStoreException {
        //使用beanName作为bean的唯一标识进行注册
        String beanName = definitionHolder.getBeanName();
        //通过beanName注册BeanDefinition
        registry.registerBeanDefinition(beanName, definitionHolder.getBeanDefinition());

registerBeanDefinition这是个接口方法,我们需要找到实体类。因为这个注册器是从上层传递进来的,所以我们要一直往回查找,最后找到这方法在DefaultListableBeanFactory类中实现

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {
        Assert.hasText(beanName, "Bean name must not be empty");
        Assert.notNull(beanDefinition, "BeanDefinition must not be null");
        if(beanDefinition instanceof AbstractBeanDefinition) {
            try {
               //注册前最后一次校验,主要检验beanDefintion中的methodOverrides时候与工厂方法并存,或者对应的方法不存在
       ((AbstractBeanDefinition)beanDefinition).validate();
            } catch (BeanDefinitionValidationException var7) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", var7);
            }
        }

        Map var3 = this.beanDefinitionMap;
        //beanDefinitionMap是全局变量,会存在并发访问,所以加锁
        synchronized(this.beanDefinitionMap) {
        //处理已经注册的BeanDefinition
            BeanDefinition oldBeanDefinition = (BeanDefinition)this.beanDefinitionMap.get(beanName);
            //如果对应的beanName已经注册并不允许覆盖,则抛出异常
            if(oldBeanDefinition != null) {
                if(!this.allowBeanDefinitionOverriding) {
                    throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound.");
                }

                if(oldBeanDefinition.getRole() < beanDefinition.getRole()) {
                    if(this.logger.isWarnEnabled()) {
                        this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + " with a framework-generated bean definition ': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                    }
                } else if(this.logger.isInfoEnabled()) {
                    this.logger.info("Overriding bean definition for bean '" + beanName + "': replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]");
                }
            } else {
            //记录beanName
                this.beanDefinitionNames.add(beanName);
                this.frozenBeanDefinitionNames = null;
            }
            //注册beanDefinition,相当于放在一个用beanName做键的map中
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        //重置beanName对应的缓存
        this.resetBeanDefinition(beanName);
    }

接下来就是注册所有的别名

        String[] aliases = definitionHolder.getAliases();
        if(aliases != null) {
            String[] var4 = aliases;
            int var5 = aliases.length;

            for(int var6 = 0; var6 < var5; ++var6) {
                String aliase = var4[var6];
                //注册别名,相当于把别名当键,beanName当值,放在map中
                registry.registerAlias(beanName, aliase);
            }
        }

    }
            } catch (BeanDefinitionStoreException var5) {
                this.getReaderContext().error("Failed to register bean definition with name '" + bdHolder.getBeanName() + "'", ele, var5);
            }
//通知监听器解析及注册完成,开发人员需要对注册时间进行监听时,将逻辑处理写入监听器中,目前没有做任何处理
            this.getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));
        }

    }

小结

经过以上分析,我们来汇总一下整个过程:
①首先是对元素进行解析,获取元素的属性,先是获取id再获取name,这个的最终目的是获取唯一标识beanName,如果id不存在,beanName用name的值,如果name也不存在就自动生成beanName。在次之前,会对元素进行进一步解析,创建BeanDefinition,将所有的属性封装进这个BeanDefinition。
②如果有自定义属性,那么解析自定义标签,对这个BeanDefinition进行修饰。
③解析完成,注册到容器中,将beanName作为键,BeanDefinition作为值存到map中,其实这个容器就是一个map。这个map存在于XmlBeanFactory所继承的DefaultListableBeanFactory中private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap(64);
。然后又将别名和beanName进行关联存到map中。
④最后发出响应事件,通知事件监听器。

alias标签解析

别名实现的方式有好多种,在之前讲的bean的标签中
<bean name="aa,bb,c">
name属性用多个逗号分隔,也能实现别名,getBean("aa")或者bb,cc都能得到这个bean,如何实现已经在之前讲过了通过对别名和和beanName的映射。
当然还有一种方式实现别名
<alias name="bean的id或者说beanName" alias="aa,bb,cc">
aa,bb,cc都是bean的别名

进入processAliasRegistration方法

protected void processAliasRegistration(Element ele) {
        //获取属性
        String name = ele.getAttribute("name");
        String alias = ele.getAttribute("alias");
        boolean valid = true;
        if(!StringUtils.hasText(name)) {
            this.getReaderContext().error("Name must not be empty", ele);
            valid = false;
        }

        if(!StringUtils.hasText(alias)) {
            this.getReaderContext().error("Alias must not be empty", ele);
            valid = false;
        }

        if(valid) {
            try {
        //注册别名                this.getReaderContext().getRegistry().registerAlias(name, alias);
            } catch (Exception var6) {
                this.getReaderContext().error("Failed to register alias '" + alias + "' for bean with name '" + name + "'", ele, var6);
            }

    //通知监听器            this.getReaderContext().fireAliasRegistered(name, alias, this.extractSource(ele));
        }

    }

import标签的解析

import标签可以导入另一个配置文件。

protected void importBeanDefinitionResource(Element ele) {
        //获取resource属性
        String location = ele.getAttribute("resource");
        if(!StringUtils.hasText(location)) {
            this.getReaderContext().error("Resource location must not be empty", ele);
        } else {
            //解析系统属性,如${user.dir}
            location = this.environment.resolveRequiredPlaceholders(location);
            Set<Resource> actualResources = new LinkedHashSet(4);
            boolean absoluteLocation = false;

            try {
                //判断是绝对URI还是相对URI
                absoluteLocation = ResourcePatternUtils.isUrl(location) || ResourceUtils.toURI(location).isAbsolute();
            } catch (URISyntaxException var11) {
                ;
            }

            int importCount;
            //如果是绝对URI直接根据地质加载对应配置文件
            if(absoluteLocation) {
                try {
                    importCount = this.getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
                    if(this.logger.isDebugEnabled()) {
                        this.logger.debug("Imported " + importCount + " bean definitions from URL location [" + location + "]");
                    }
                } catch (BeanDefinitionStoreException var10) {
                    this.getReaderContext().error("Failed to import bean definitions from URL location [" + location + "]", ele, var10);
                }
            } else {
                try {
                    //如果是相对地址就根据相对对地址计算出绝对地址
                    Resource relativeResource = this.getReaderContext().getResource().createRelative(location);
                    if(relativeResource.exists()) {
                        //进行解析
                        importCount = this.getReaderContext().getReader().loadBeanDefinitions(relativeResource);
                        actualResources.add(relativeResource);
                    } else {
                    //如果解析不成功,则使用默认解析器进行解析
                        String baseLocation = this.getReaderContext().getResource().getURL().toString();

                        importCount = this.getReaderContext().getReader().loadBeanDefinitions(StringUtils.applyRelativePath(baseLocation, location), actualResources);
                    }

                    if(this.logger.isDebugEnabled()) {
                        this.logger.debug("Imported " + importCount + " bean definitions from relative location [" + location + "]");
                    }
                } catch (IOException var8) {
                    this.getReaderContext().error("Failed to resolve current resource location", ele, var8);
                } catch (BeanDefinitionStoreException var9) {
                    this.getReaderContext().error("Failed to import bean definitions from relative location [" + location + "]", ele, var9);
                }
            }
            //解析后进行进行监听器激活
            Resource[] actResArray = (Resource[])actualResources.toArray(new Resource[actualResources.size()]);
            this.getReaderContext().fireImportProcessed(location, actResArray, this.extractSource(ele));
        }
    }

嵌入式beans标签解析

这个无非是递归调用对beans的解析

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值