Spring IOC(二)beanName 别名管理

Spring IOC(二)beanName 别名管理

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

一、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) 的队列。



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

原文地址:https://www.cnblogs.com/binarylei/p/10344067.html

时间: 2024-11-13 07:57:11

Spring IOC(二)beanName 别名管理的相关文章

Spring——IOC(二)

三.Id和Name 在Spring的配置文件中,bean的id属性和name属性可以相互替换. (1) <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xs

Spring:源码解读Spring IOC原理

Spring IOC设计原理解析:本文乃学习整理参考而来 一. 什么是Ioc/DI? 二. Spring IOC体系结构 (1) BeanFactory (2) BeanDefinition 三. IoC容器的初始化 1. XmlBeanFactory(屌丝IOC)的整个流程 2. FileSystemXmlApplicationContext 的IOC容器流程 1.高富帅IOC解剖 2. 设置资源加载器和资源定位 3.AbstractApplicationContext的refresh函数载入

Spring?IOC设计原理解析:本文乃学习整理参考而来

Spring IOC设计原理解析:本文乃学习整理参考而来 一. 什么是Ioc/DI? 二. Spring IOC体系结构 (1) BeanFactory (2) BeanDefinition 三. IoC容器的初始化 1. XmlBeanFactory(屌丝IOC)的整个流程 2. FileSystemXmlApplicationContext 的IOC容器流程 1.高富帅IOC解剖 2. 设置资源加载器和资源定位 3.AbstractApplicationContext的refresh函数载入

Spring:源码解读Spring IOC原理--(转载)

转自:http://www.cnblogs.com/ITtangtang/p/3978349.html 这篇文章个人觉得整理的很不错,很值得学习,为了方便自己学习和大家学习,特转载此文保留.请尊重原创~~ Spring IOC设计原理解析:本文乃学习整理参考而来 一. 什么是Ioc/DI? 二. Spring IOC体系结构 (1) BeanFactory (2) BeanDefinition 三. IoC容器的初始化 1. XmlBeanFactory(屌丝IOC)的整个流程 2. FileS

Spring IOC原理解读 面试必读

Spring IOC设计原理解析:本文乃学习整理参考而来 一. 什么是Ioc/DI? 二. Spring IOC体系结构 (1) BeanFactory (2) BeanDefinition 三. IoC容器的初始化 1. XmlBeanFactory(屌丝IOC)的整个流程 2. FileSystemXmlApplicationContext 的IOC容器流程 1.高富帅IOC解剖 2. 设置资源加载器和资源定位 3.AbstractApplicationContext的refresh函数载入

Spring笔记(一):Ioc 之 Bean的管理

前提: 1.需要 spring.dom4j.junit.commons-logging等的jar包, 配置web.xml,新增 applicationContext.xml 2.Spring主要核心是: 1)控制反转(IOC):以前传统的java开发模式中,当需要一个对象时我们,我们会自己使用new或者getInstance等直接或者间接调用构造方法创建一个对象,而在Spring开发模式中,Spring容器使用了工厂模式为我们创建了所需要的对象,我们使用时不需要自己去创建,直接调用Spring为

【Spring IoC】Spring Bean(二)

一.Spring Bean的定义 被称作 bean 的对象是构成应用程序的支柱也是由 Spring IoC 容器管理的.bean 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象.这些 bean 是由容器提供的配置元数据创建的. bean 定义包含称为配置元数据的信息.主要包括: 如何创建一个 bean bean 的生命周期的详细信息 bean 的依赖关系 每个 bean 可以定义的属性有: class:必填,用来定义类的全限定名(包名+类名).只有子类Bean不用定义该属性

Spring学习(二)spring ioc注入的三种方式

一.spring ioc注入有哪三种方式: a setter 原理 : 在目标对象中,定义需要注入的依赖对象对应的属性和setter方法:"让ioc容器调用该setter方法",将ioc容器实例化的依赖对象通过setter注入给目标对象,封装在目标对象的属性中. b 构造器 原理 : 为目标对象提供一个构造方法,在构造方法中添加一个依赖对象对应的参数.ioc容器解析时,实例化目标对象时会自动调用构造方法,ioc只需要为构造器中的参数进行赋值:将ioc实例化的依赖对象作为构造器的参数传入

Spring框架学习之IOC(二)

Spring框架学习之IOC(二) 接着昨天的内容,下面开始IOC基于注解装配相关的内容 在 classpath 中扫描组件 <context:component-scan> 特定组件包括: –@Component: 基本注解, 标识了一个受 Spring 管理的组件 –@Respository: 标识持久层组件 –@Service: 标识服务层(业务层)组件 –@Controller: 标识表现层组件 对于扫描到的组件, Spring 有默认的命名策略: 使用非限定类名, 第一个字母小写.