這個接口擴展了上文提到的別名註冊接口,提供了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); }
雖然還有一些別的實現,但咱們beanFactory的分析整個都是基於DefaultListableBeanFactory的繼承體系來分析的,能夠看到這個類直接實現了咱們的bean定義註冊接口,下面分析它的相關實現安全
private volatile List<String> beanDefinitionNames = new ArrayList<>(256); private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
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); } } } }
這裏相似於註冊,再也不分析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); }
這裏有意思的是若是已凍結的bean定義列表有數據,就返回這個,不然就返回實時的bean定義列表數據,至於爲什麼這麼作有待思考。this
public String[] getBeanDefinitionNames() { String[] frozenNames = this.frozenBeanDefinitionNames; if (frozenNames != null) { return frozenNames.clone(); } else { return StringUtils.toStringArray(this.beanDefinitionNames); } }
這個方法實現並不在DefaultListableBeanFactory中,由於DefaultListableBeanFactory還繼承了AbstractBeanFactory,在它的抽象父類中實現了該方法,這也說明接口中的方法不必定要在一個類中所有實現,只要可以保證經過繼承實現也是能夠的!線程
public boolean isBeanNameInUse(String beanName) { return isAlias(beanName) || containsLocalBean(beanName) || hasDependentBean(beanName); }
這個邏輯並不複雜,也就是判斷beanName是否被別名佔用了,容器本地是否包含了beanName,beanName是不是某一個bean的依賴code