spring 之 import标签、alias标签、beans标签 解析

继续接着Spring 加载、解析applicationContext.xml 流程解析 import 、 alias、beans 标签。

DefaultBeanDefinitionDocumentReader.parseDefaultElement()

1. import 标签解析

标签示例

<import resource="user-appalicationContext.xml"/>

解析import 标签

入口类、方法DefaultBeanDefinitionDocumentReader.importBeanDefinitionResource();

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

    // 解析系统属性。比如 "${user.dir}"
    location = getReaderContext().getEnvironment().resolveRequiredPlaceholders(location);

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

    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*:"
    }
    // 绝对路径
    if (absoluteLocation) {
        try {
            //加载xml配置文件,并解析资源
            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 relativeResource = getReaderContext().getResource().createRelative(location);
            if (relativeResource.exists()) {
                //加载xml文件,并解析
                importCount = getReaderContext().getReader().loadBeanDefinitions(relativeResource);
                actualResources.add(relativeResource);
            }else {
                // 获取URL 路径,并解析文件
                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[actualResources.size()]);
    getReaderContext().fireImportProcessed(location, actResArray, extractSource(ele));
}
  1. 获取resource属性
  2. 解析路径中的系统属性,格式如“${user.dir}”
  3. 判断location是绝对路径还是相对路径
  4. 如果是绝对路径,则递归调用bean的解析过程。重新执行这个流程 Spring 加载、解析applicationContext.xml 流程
  5. 如果相对路径,则把相对路径转换成绝对路径,在解析
  6. 通过监听器、解析完成

2. alias 标签解析

alias 标签示例

<bean id="user" class="cn.com.infcn.test.User"></bean>
<alias name="user" alias="myUser" />

解析 alias 标签

DefaultBeanDefinitionDocumentReader.processAliasRegistration()

protected void processAliasRegistration(Element ele) {
    //获取 name属性
    String name = ele.getAttribute(NAME_ATTRIBUTE);
    //获取 alias 属性
    String alias = ele.getAttribute(ALIAS_ATTRIBUTE);
    boolean valid = true;
    //验证 name 是否为空
    if (!StringUtils.hasText(name)) {
        getReaderContext().error("Name must not be empty", ele);
        valid = false;
    }
    //验证 alias 是否为空
    if (!StringUtils.hasText(alias)) {
        getReaderContext().error("Alias must not be empty", ele);
        valid = false;
    }
    if (valid) {
        try {
            //把 alias 注册到 SimpleAliasRegistry.aliasMap 中
            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));
    }
}
  1. 解析 alias 标签,获取 name 和 alias 属性值。
  2. 把 name 和 alias 注册到 SimpleAliasRegistry.aliasMap 属性中。

SimpleAliasRegistry 源码

public class SimpleAliasRegistry implements AliasRegistry {

    private final Map<String, String> aliasMap = new ConcurrentHashMap<>(16);

    @Override
    public void registerAlias(String name, String alias) {
        Assert.hasText(name, "'name' must not be empty");
        Assert.hasText(alias, "'alias' must not be empty");
        if (alias.equals(name)) {
            this.aliasMap.remove(alias);
        }else {
            String registeredName = this.aliasMap.get(alias);
            if (registeredName != null) {
                if (registeredName.equals(name)) {
                    // An existing alias - no need to re-register
                    return;
                }
                if (!allowAliasOverriding()) {
                    throw new IllegalStateException("Cannot register alias '" + alias + "' for name '" +
                            name + "': It is already registered for name '" + registeredName + "'.");
                }
            }
            checkForAliasCircle(name, alias);
            this.aliasMap.put(alias, name);
        }
    }

    protected boolean allowAliasOverriding() {
        return true;
    }
    ......

3. beans 标签解析

beans标签示例

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

    <bean id="user" class="cn.com.infcn.test.User"></bean>
    <beans>
        ......
    </beans>
</beans>

beans 标签解析 又调用了doRegisterBeanDefinitions() 方法,这个方法在Spring 加载、解析applicationContext.xml 流程中已经介绍过了。 跟import 解析都类似。又相当于重新执行解析了一边 bean 标签一样。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏chenssy

【死磕 Spring】----- IOC 之解析 bean 标签:解析自定义标签

前面四篇文章都是分析 Bean 默认标签的解析过程,包括基本属性、六个子元素(meta、lookup-method、replaced-method、constr...

12940
来自专栏雪胖纸的玩蛇日常

Uncaught SyntaxError: Unexpected token ' in JSON at position 1

1.5K30
来自专栏Java与Android技术栈

用kotlin打印出漂亮的android日志写在最后

Kotlin号称是Android版本的swift,距离它1.0正式版本的推出快一年了。它像swift一样,可以写客户端也可以写服务端。由于公司项目比较繁忙,我一...

15620
来自专栏chenssy

【死磕 Spring】----- IOC 之 IOC 初始化总结

前面 13 篇博文从源码层次分析了 IOC 整个初始化过程,这篇就这些内容做一个总结将其连贯起来。

9910
来自专栏Golang语言社区

用Go实现一门解释型语言

A interpreter language implementation in Go

10220
来自专栏Java与Android技术栈

基于RxJava2实现的简单图片爬虫

今年十月份以来,跟朋友尝试导入一些图片到tensorflow来生成模型,这就需要大量的图片。刚开始我只写了一个简单的HttpClient程序来抓取图片,后来为了...

16920
来自专栏Android开发指南

Android优化指南

54870
来自专栏葡萄城控件技术团队

Wijmo 更优美的jQuery UI部件集:导出Wijmo的GridView到Excel

Wijmo GridView 控件不提供导出Excel文件的方法。本篇博客介绍一种将Wijmo的GridView控件保存到Excel的简单方法。你可以使用同样的...

26680
来自专栏Golang语言社区

GoLang并发控制(下)

context的字面意思是上下文,是一个比较抽象的词,字面上理解就是上下层的传递,上会把内容传递给下,在go中程序单位一般为goroutine,这里的上下文便是...

35130
来自专栏一个会写诗的程序员的博客

CodeMirror 代码渲染神器的极简入门实例

2.7K10

扫码关注云+社区

领取腾讯云代金券