美文网首页
第3章 默认标签解析补充

第3章 默认标签解析补充

作者: 十丈_红尘 | 来源:发表于2019-01-13 22:10 被阅读0次

3.3 import标签的解析

  对于Spring配置文件的编写,如果经历过庞大项目的人,都有那种恐惧的心理,太多的配置文件.不过,分模块是大多数人能想到的办法,但是,怎么分模块,那就仁者见仁 智者见智了.使用import是个好办法,例如我们可以构造这样的Spring配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <import resource="customerContext.xml" />
    <import resource="systemContext.xml" />
    ... ...
</beans>

  applicationContext.xml文件中使用import的方式导入有模块配置文件,以后若有新模块的加入,那就可以简单修改这个文件即可.这样大大简化了配置后期维护的复杂度,并使配置模块化,易于管理.我们来看看Spring是如何解析import配置文件的.

protected void processAliasRegistration(Element ele) {
        // 获取beanName
        String name = ele.getAttribute(NAME_ATTRIBUTE);
        // 获取alias
        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 {
                // 注册alias
                getReaderContext().getRegistry().registerAlias(name, alias);
            }
            catch (Exception ex) {
                getReaderContext().error("Failed to register alias '" + alias +
                        "' for bean with name '" + name + "'", ele, ex);
            }
            // 别名注册后通知监听器做相应的处理
            getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));
        }
    }

    protected void importBeanDefinitionResource(Element ele) {
        // 获取resource属性
        String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
        // 如果不存在resource属性则不做任何处理
        if (!StringUtils.hasText(location)) {
            getReaderContext().error("Resource location must not be empty", ele);
            return;
        }

        // Resolve system properties: e.g. "${user.dir}"
        // 解析系统属性,格式如: "${user.dir}"
        location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);

        Set<Resource> actualResources = new LinkedHashSet<>(4);

        // Discover whether the location is an absolute or relative URI
        // 判断location是绝对URI还是相对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?
        // 如果是绝对URI则直接根据地址加载对应的配置文件
        if (absoluteLocation) {
            try {
                int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
                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存在多个子实现类,如VfsResource, FileSystemResource等,
                // 而每个resource的createRelative方式实现都不一样,所以这里先使用子类的方法尝试解析
                Resource relativeResource = getReaderContext().getResource().createRelative(location);
                if (relativeResource.exists()) {
                    importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
                    actualResources.add(relativeResource);
                }
                else {
                    // 如果解析不成功,则使用默认的解析器ResourcePatternResolver进行解析.
                    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));
    }

  上面的代码不难,相信配合注解会很好理解的,我们总结一下大致流程便于大家更好的梳理,在解析<import>标签时,Spring进行解析的步骤大致如下.
 (1) 获取resource属性锁表示的路径;
 (2) 解析路径中的系统属性,格式如"${user.dir}";
 (3) 判定location是绝对路径还是相对路径;
 (4) 如果是绝对路径则递归调用bean的解析过程,进行另一次的解析;
 (5) 如果是相对路径则计算出绝对路径并进行解析;
 (6) 通知监听器,解析完成.


3.4 嵌入式beans标签的解析

  对于嵌入式的beans标签,相信大家使用过或者至少接触过,非常类似于import标签所提供的功能,使用如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="aa" class="test.aa" />
    <beans></beans>
</beans>

  对于嵌入式beans标签来讲,并没有太多可讲,与单独的配置文件并没有太大的差别,无非是递归调用beans的解析过程,相信大家根据之前讲解过的内容已经有能力理解其中的奥秘了.

相关文章

网友评论

      本文标题:第3章 默认标签解析补充

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