Spring IOC(二)beanName 別名管理

Spring IOC(二)beanName 別名管理

Spring 系列目錄(http://www.javashuo.com/article/p-kqecupyl-bm.html)html

BeanDefinitionRegistry 類圖

1、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。java

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) 屬性spring

SimpleAliasRegistry 內部維護了一個隊列,存儲的是 <alais, name>api

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

(2) registerAliaside

註冊一個 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) hasAliasthis

判斷指定的 name 是否有 alias 的別名。code

// 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) getAliaseshtm

獲取指定 bean 的全部別名。blog

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

2、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) 的隊列。


天天用心記錄一點點。內容也許不重要,但習慣很重要!

相關文章
相關標籤/搜索