Spring 水滴石穿(三) 工廠實現之bean定義註冊BeanDefinitionRegistry

BeanDefinitionRegistry接口

這個接口擴展了上文提到的別名註冊接口,提供了bean定義的註冊,註銷等功能緩存

public interface BeanDefinitionRegistry extends AliasRegistry {
    //註冊bean定義,可能拋出異常
    void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException;

    //註銷bean定義,可能拋出異常
    void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    //獲取bean定義
    BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;

    //是否包含bean定義
    boolean containsBeanDefinition(String beanName);

    //獲取全部bean定義的名字
    String[] getBeanDefinitionNames();

    //返回bean定義的總數
    int getBeanDefinitionCount();

    //是否給定的bean在使用了
    boolean isBeanNameInUse(String beanName);

}

DefaultListableBeanFactory實現

雖然還有一些別的實現,但咱們beanFactory的分析整個都是基於DefaultListableBeanFactory的繼承體系來分析的,能夠看到這個類直接實現了咱們的bean定義註冊接口,下面分析它的相關實現安全

與bean定義有關的屬性

private volatile List<String> beanDefinitionNames = new ArrayList<>(256);

private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

registerBeanDefinition

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {

        if (beanDefinition instanceof AbstractBeanDefinition) {
            try {
            //驗證bean定義
                ((AbstractBeanDefinition) beanDefinition).validate();
            }
            catch (BeanDefinitionValidationException ex) {
                throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName,
                        "Validation of bean definition failed", ex);
            }
        }

        BeanDefinition existingDefinition = this.beanDefinitionMap.get(beanName);
        if (existingDefinition != null) {
        //是否容許bean定義重寫是能夠配置的
            if (!isAllowBeanDefinitionOverriding()) {
                throw new BeanDefinitionOverrideException(beanName, beanDefinition, existingDefinition);
            }
            this.beanDefinitionMap.put(beanName, beanDefinition);
        }
        else {
        //是否已經建立了bean
            if (hasBeanCreationStarted()) {
                // Cannot modify startup-time collection elements anymore (for stable iteration)
                synchronized (this.beanDefinitionMap) {
                    this.beanDefinitionMap.put(beanName, beanDefinition);
                    List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
                    updatedDefinitions.addAll(this.beanDefinitionNames);
                    updatedDefinitions.add(beanName);
                    this.beanDefinitionNames = updatedDefinitions;
                    removeManualSingletonName(beanName);
                }
            }
            else {
                // Still in startup registration phase
                this.beanDefinitionMap.put(beanName, beanDefinition);
                this.beanDefinitionNames.add(beanName);
                //移除手動單例名字,將註冊的bean定義優先級更高
                removeManualSingletonName(beanName);
            }
            //不管如何,解凍已凍結的bean定義
            this.frozenBeanDefinitionNames = null;
        }

        //若是原本就存在bean定義,或者這個bean已經處於建立中了,須要重置bean定義
        if (existingDefinition != null || containsSingleton(beanName)) {
            resetBeanDefinition(beanName);
        }
        else if (isConfigurationFrozen()) {
            clearByTypeCache();
        }
    }

有幾個要注意的地方
1.((AbstractBeanDefinition) beanDefinition).validate()併發

bean定義除了這個抽象bean定義仍是基於註解的bean定義,只有在抽象bean定義的時候纔會去作驗證,後面在分析這個方法
2.在往map添加新數據前有個hasBeanCreationStarted方法
若是都沒有建立好的bean,說明當前必定沒有對beanName集合的遍歷,要知道遍歷的時候去添加數據是不穩定的,有可能拋出併發修改異常,因此這裏經過這個方法來判斷。我的理解,深刻分析之後也沒發覺這個方法是線程安全的,感受又不是這個緣由?
3.後續處理:舊的bean定義存在,或者單例的bean已經在建立中
這種狀況意味着對舊的bean定義重寫了,但何時會出現沒有舊的bean定義可是單例bean已經在建立了呢?能夠看到有一條關鍵路徑就是重置bean定義,這裏能夠認爲是作一些清理工做,好比移除合併後的bean定義
protected void resetBeanDefinition(String beanName) {
        //若是已經被建立,移除合併後的bean定義
        clearMergedBeanDefinition(beanName);

        //移除緩存的單例
        destroySingleton(beanName);

        //通知全部的後置處理器,指定的bean定義被重置了
        for (BeanPostProcessor processor : getBeanPostProcessors()) {
            if (processor instanceof MergedBeanDefinitionPostProcessor) {
                ((MergedBeanDefinitionPostProcessor) processor).resetBeanDefinition(beanName);
            }
        }

        // 遞歸重置全部的子bean定義
        for (String bdName : this.beanDefinitionNames) {
            if (!beanName.equals(bdName)) {
                BeanDefinition bd = this.beanDefinitionMap.get(bdName);
                // Ensure bd is non-null due to potential concurrent modification of beanDefinitionMap.
                if (bd != null && beanName.equals(bd.getParentName())) {
                    resetBeanDefinition(bdName);
                }
            }
        }
    }

removeBeanDefinition

這裏相似於註冊,再也不分析ide

public void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {

        BeanDefinition bd = this.beanDefinitionMap.remove(beanName);
        if (bd == null) {
            throw new NoSuchBeanDefinitionException(beanName);
        }
        if (hasBeanCreationStarted()) {
            synchronized (this.beanDefinitionMap) {
                List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames);
                updatedDefinitions.remove(beanName);
                this.beanDefinitionNames = updatedDefinitions;
            }
        }
        else {
            // Still in startup registration phase
            this.beanDefinitionNames.remove(beanName);
        }
        this.frozenBeanDefinitionNames = null;

        resetBeanDefinition(beanName);
    }

getBeanDefinitionNames

這裏有意思的是若是已凍結的bean定義列表有數據,就返回這個,不然就返回實時的bean定義列表數據,至於爲什麼這麼作有待思考。this

public String[] getBeanDefinitionNames() {
        String[] frozenNames = this.frozenBeanDefinitionNames;
        if (frozenNames != null) {
            return frozenNames.clone();
        }
        else {
            return StringUtils.toStringArray(this.beanDefinitionNames);
        }
    }

isBeanNameInUse

這個方法實現並不在DefaultListableBeanFactory中,由於DefaultListableBeanFactory還繼承了AbstractBeanFactory,在它的抽象父類中實現了該方法,這也說明接口中的方法不必定要在一個類中所有實現,只要可以保證經過繼承實現也是能夠的!線程

public boolean isBeanNameInUse(String beanName) {
        return isAlias(beanName) || containsLocalBean(beanName) || hasDependentBean(beanName);
    }

這個邏輯並不複雜,也就是判斷beanName是否被別名佔用了,容器本地是否包含了beanName,beanName是不是某一個bean的依賴code

相關文章
相關標籤/搜索