spring中默认标签alias、import标签解析

1、Alias标签

在bean标签里边有一个alias属性和name属性,可以指定bean的别名,但是有的场景下,在定义bean的时候就把他的别名都指定好是不适用的。
比如这个Bean在组件A中,想把他叫做componentA,但是在组件B中又想把他叫做componetB,所以还有一个单独的标签:< alias>专门解决上述场景的。

<bean id="myBean" class="com.itpluto.MyBean"></bean>
<alias name="myBean" alias="componetA">
<alias name="myBean" alias="componetB">

这样一来,每个组件及程序就可以通过唯一名字来引用同一个数据源而互不干扰。

Spring对alias的解析

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;
    }
    // 上面两个判断可以知道,alias标签必须包含两个属性:name、alias
    if (valid) {
        try {
            // 注册别名
            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));
    }
}

其实和之前bean中的alias解析一样,都是把别名与beanName组成一对注册到register中。

 

2、Import标签

import的使用场景主要是因为项目比较大,配置文件非常多的时候,会进行分模块,这个时候就可以用到import这个标签了。

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

这样以后有新的模块加入,就可以简单修改这个文件了,这样大大简化了配置后期维护的复杂度,并且易于管理。

protected void importBeanDefinitionResource(Element ele) {
    // 获取resource属性
    String location = ele.getAttribute(RESOURCE_ATTRIBUTE);
    if (!StringUtils.hasText(location)) {
        getReaderContext().error("Resource location must not be empty", ele);
        return;
    }

    // Resolve system properties: e.g. "${user.dir}"
    // 把resource属性的值进行处理,如果有占位符的,需要进行替换
    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 {
        // 判断location是绝对路径还是相对路径
        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 {
            // 绝对路径直接解析,并且加载beanDefinition即可
            int importCount = getReaderContext().getReader().loadBeanDefinitions(location, actualResources);
            if (logger.isTraceEnabled()) {
                logger.trace("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 {
        // 相对路径则根据相对地址计算绝对地址	
        try {
            int importCount;
            // Resource之前分析过有很多子类实现,比如FileSystemResource、ClassPathResource等,
            // 每个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.isTraceEnabled()) {
                logger.trace("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、获取resource属性的值。
2、解析路径中的系统属性,比如:${user.dir}。
3、根据resource的值来判断是绝对路径还是相对路径,如果是绝对路径直接加载解析文件即可,如果是相对路径要先计算出绝对路径。
4、通知监听器,解析完成。

posted @ 2023-06-05 16:04  BlogZero  阅读(268)  评论(0)    收藏  举报