• Spring IOC(二)beanName 别名管理


    Spring IOC(二)beanName 别名管理

    Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)

    BeanDefinitionRegistry 类图

    一、AliasRegistry

    public interface AliasRegistry {
        void registerAlias(String name, String alias);
        void removeAlias(String alias);
        boolean isAlias(String name);
        String[] getAliases(String name);
    }
    

    AliasRegistry 接口十分简单,提供了注册、获取及删除指定 beanName 的别名的功能。下面我们重点关注一下它的默认的实现 SimpleAliasRegistry。

    1.2 API 使用

    @Test
    public void test() {
        SimpleAliasRegistry aliasRegistry = new SimpleAliasRegistry();
        aliasRegistry.registerAlias("beanA", "beanA_alias1");
        aliasRegistry.registerAlias("beanA_alias1", "beanA_alias2");
    
        // 1. 获取别名对应的真实名称
        Assert.assertEquals("beanA", aliasRegistry.canonicalName("beanA_alias1"));
        Assert.assertEquals("beanA", aliasRegistry.canonicalName("beanA_alias2"));
    
        // 2. 获取 beanA 的所有别名
        Assert.assertEquals(2, aliasRegistry.getAliases("beanA").length);
    
        Assert.assertTrue(aliasRegistry.isAlias("beanA_alias1"));
        Assert.assertTrue(aliasRegistry.hasAlias("beanA", "beanA_alias2"));
    }
    

    1.2 SimpleAliasRegistry 源码分析

    (1) 属性

    SimpleAliasRegistry 内部维护了一个队列,存储的是 <alais, name>

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

    (2) registerAlias

    注册一个 alias

    @Override
    public void registerAlias(String name, String alias) {
        synchronized (this.aliasMap) {
            // 1. 别名和 bean 的名称相同,不需要注册,如果注册了也要删除
            if (alias.equals(name)) {
                this.aliasMap.remove(alias);
            } else {
                String registeredName = this.aliasMap.get(alias);
                // 2. 别名已经注册,如果注册的名称不相同是否允许覆盖
                if (registeredName != null) {
                    if (registeredName.equals(name)) {
                        return;
                    }
                    // 默认返回 true
                    if (!allowAliasOverriding()) {
                        throw new IllegalStateException("");
                    }
                }
                // 3. 注册前检查是否出现了循环注册,如注册 (a, b) 时已经注册了 (b, a)
                checkForAliasCircle(name, alias);
                this.aliasMap.put(alias, name);
            }
        }
    }
    

    (3) hasAlias

    判断指定的 name 是否有 alias 的别名。

    // a -> b -> c -> d -> e -> canonicalName,反向查找先找到最后一个 name
    // 然后一个一个判断是不是要查找的 alias
    public boolean hasAlias(String name, String alias) {
        for (Map.Entry<String, String> entry : this.aliasMap.entrySet()) {
            String registeredName = entry.getValue();
            if (registeredName.equals(name)) {
                String registeredAlias = entry.getKey();
                if (registeredAlias.equals(alias) || hasAlias(registeredAlias, alias)) {
                    return true;
                }
            }
        }
        return false;
    }
    
    // 检查循环依赖
    protected void checkForAliasCircle(String name, String alias) {
        if (hasAlias(alias, name)) {
            throw new IllegalStateException("");
        }
    }
    

    (4) getAliases

    获取指定 bean 的所有别名。

    @Override
    public String[] getAliases(String name) {
        List<String> result = new ArrayList<>();
        synchronized (this.aliasMap) {
            retrieveAliases(name, result);
        }
        return StringUtils.toStringArray(result);
    }
    private void retrieveAliases(String name, List<String> result) {
        this.aliasMap.forEach((alias, registeredName) -> {
            if (registeredName.equals(name)) {
                result.add(alias);
                retrieveAliases(alias, result);
            }
        });
    }
    

    (5) canonicalName

    获取一个 alias 的真实 name。

    public String canonicalName(String name) {
        String canonicalName = name;
        // Handle aliasing...
        String resolvedName;
        do {
            resolvedName = this.aliasMap.get(canonicalName);
            if (resolvedName != null) {
                canonicalName = resolvedName;
            }
        }
        while (resolvedName != null);
        return canonicalName;
    }
    

    (5) resolveAliases

    解析 alias 和 name 中的占位符。

    public void resolveAliases(StringValueResolver valueResolver) {
        synchronized (this.aliasMap) {
            // 因为遍历时要修改 Map 集合,所以 copy 了一个新集合用于遍历
            Map<String, String> aliasCopy = new HashMap<>(this.aliasMap);
            aliasCopy.forEach((alias, registeredName) -> {
                String resolvedAlias = valueResolver.resolveStringValue(alias);
                String resolvedName = valueResolver.resolveStringValue(registeredName);
                // 1. 不存在或 resolvedAlias=resolvedName 时直接干掉
                if (resolvedAlias == null || resolvedName == null || resolvedAlias.equals(resolvedName)) {
                    this.aliasMap.remove(alias);
                // 2. 别名解析后变化,两种情况:一是真实别名已经注册;二是没有注册。
                //    真实别名已经注册又有两种情况:真实别名获取的 name 和要注册的 name 是否相等
                } else if (!resolvedAlias.equals(alias)) {
                    String existingName = this.aliasMap.get(resolvedAlias);
                    // 2.1 别名已存在且相等只需要将含有占位符的别名删除即可,否则抛出异常
                    if (existingName != null) {
                        if (existingName.equals(resolvedName)) {
                            this.aliasMap.remove(alias);
                            return;
                        }
                        throw new IllegalStateException();
                    }
                    // 2.2 不存在,注册前同样需要检查循环依赖
                    checkForAliasCircle(resolvedName, resolvedAlias);
                    this.aliasMap.remove(alias);
                    this.aliasMap.put(resolvedAlias, resolvedName);
                // 3. 真实名称解析后变化直接替换
                } else if (!registeredName.equals(resolvedName)) {
                    this.aliasMap.put(alias, resolvedName);
                }
            });
        }
    }
    

    二、BeanDefinitionRegistry

    BeanDefinitionRegistry 管理所有注册在 BeanFactory 上的 BeanDefinitio

    public interface BeanDefinitionRegistry extends AliasRegistry {
        // 1. BeanDefinition 的注册、删除、获取
        void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
                throws BeanDefinitionStoreException;
        void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
        BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;
    
        // 2. 其余的查询操作
        boolean containsBeanDefinition(String beanName);
        String[] getBeanDefinitionNames();
        int getBeanDefinitionCount();
    
        // 3. BeanFactory 是否注册了这个 bean,最简单的办法是 isAlias(beanName) || containsBeanDefinition(beanName)    
        boolean isBeanNameInUse(String beanName);
    }
    

    BeanDefinitionRegistry 的默认实现为 SimpleBeanDefinitionRegistry,它的实现也十分简单,内部维护 Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64) 的队列。


    每天用心记录一点点。内容也许不重要,但习惯很重要!

  • 相关阅读:
    第三节课 字符串拼接、格式化输出、深浅复制
    第四节课 集合、字典、运算符
    python-模块系列
    python正则表达式
    python第二天
    Python-第一天
    SQL SERVER 最近查询过的语句
    razor page 页面
    RAZOR显示表格数据
    邮件模板 C#
  • 原文地址:https://www.cnblogs.com/binarylei/p/10344067.html
Copyright © 2020-2023  润新知