欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-04-30 11:42:03
...

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

DefaultBeanDefinitionDocumentReader.parseDefaultElement()
spring 之 import标签、alias标签、beans标签 解析

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 标签一样。

本人简书blog地址:http://www.jianshu.com/u/1f0067e24ff8    
点击这里快速进入简书

GIT地址:http://git.oschina.net/brucekankan/
点击这里快速进入GIT