將定義 bean 的資源檔案解析成 BeanDefinition 後需要將其註入容器中,這個過程由 BeanDefinitionRegistry 來完成。
BeanDefinitionRegistry:向登錄檔中註冊 BeanDefinition 實體,完成註冊的過程。
下圖是 BeanDefinitionRegistry 類結構圖:

BeanDefinitionRegistry 繼承了 AliasRegistry 介面,其核心子類有三個:SimpleBeanDefinitionRegistry、DefaultListableBeanFactory、GenericApplicationContext。
AliasRegistry
用於別名管理的通用型介面,作為 BeanDefinitionRegistry 的頂層介面。 AliasRegistry 定義了一些別名管理的方法。
public interface AliasRegistry {void registerAlias(String name, String alias);void removeAlias(String alias);boolean isAlias(String name);String[] getAliases(String name);}
BeanDefinitionRegistry
BeanDefinition 的註冊介面,如 RootBeanDefinition 和 ChildBeanDefinition。它通常由 BeanFactories 實現,在 Spring 中已知的實現者為:DefaultListableBeanFactory 和 GenericApplicationContext。BeanDefinitionRegistry 是 Spring 的 Bean 工廠包中唯一封裝 BeanDefinition 註冊的介面。
BeanDefinitionRegistry 介面定義了關於 BeanDefinition 註冊、登出、查詢等一系列的操作。
public interface BeanDefinitionRegistry extends AliasRegistry {// 往登錄檔中註冊一個新的 BeanDefinition 實體void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException;// 移除登錄檔中已註冊的 BeanDefinition 實體void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;// 從註冊中取得指定的 BeanDefinition 實體BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException;// 判斷 BeanDefinition 實體是否在登錄檔中(是否註冊)boolean containsBeanDefinition(String beanName);// 取得登錄檔中所有 BeanDefinition 實體的 beanName(標識)String[] getBeanDefinitionNames();// 傳回登錄檔中 BeanDefinition 實體的數量int getBeanDefinitionCount();// beanName(標識)是否被佔用boolean isBeanNameInUse(String beanName);}
SimpleBeanDefinitionRegistry
SimpleBeanDefinitionRegistry 是 BeanDefinitionRegistry 一個簡單的實現,它還繼承 SimpleAliasRegistry( AliasRegistry 的簡單實現),它僅僅只提供註冊表功能,無工廠功能。
SimpleBeanDefinitionRegistry 使用 ConcurrentHashMap 來儲存註冊的 BeanDefinition。
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(64);
他對註冊其中的 BeanDefinition 都是基於 beanDefinitionMap 這個集合來實現的,如下:
@Overridepublic void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {Assert.hasText(beanName, "'beanName' must not be empty");Assert.notNull(beanDefinition, "BeanDefinition must not be null");this.beanDefinitionMap.put(beanName, beanDefinition);}@Overridepublic void removeBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {if (this.beanDefinitionMap.remove(beanName) == null) {throw new NoSuchBeanDefinitionException(beanName);}}@Overridepublic BeanDefinition getBeanDefinition(String beanName) throws NoSuchBeanDefinitionException {BeanDefinition bd = this.beanDefinitionMap.get(beanName);if (bd == null) {throw new NoSuchBeanDefinitionException(beanName);}return bd;}
實現簡單、粗暴。
DefaultListableBeanFactory
DefaultListableBeanFactory,ConfigurableListableBeanFactory(其實就是 BeanFactory ) 和 BeanDefinitionRegistry 介面的預設實現:一個基於 BeanDefinition 元資料的完整 bean 工廠。所以相對於 SimpleBeanDefinitionRegistry 而言,DefaultListableBeanFactory 則是一個具有註冊功能的完整 bean 工廠。它同樣是用 ConcurrentHashMap 資料結構來儲存註冊的 BeanDefinition。
// 登錄檔,由 BeanDefinition 的標識 (beanName) 與其實體組成private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, bean>(64);// 標識(beanName)集合private final List<String> beanDefinitionNames = new ArrayList<String>(64);
在看 registerBeanDefinition():
public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)throws BeanDefinitionStoreException {// 省略其他程式碼else {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;if (this.manualSingletonNames.contains(beanName)) {Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames);updatedSingletons.remove(beanName);this.manualSingletonNames = updatedSingletons;}}}else {// 註冊 BeanDefinitionthis.beanDefinitionMap.put(beanName, beanDefinition);this.beanDefinitionNames.add(beanName);this.manualSingletonNames.remove(beanName);}this.frozenBeanDefinitionNames = null;}if (existingDefinition != null || containsSingleton(beanName)) {resetBeanDefinition(beanName);}}
其實上面一堆程式碼最重要就只有一句:
this.beanDefinitionMap.put(beanName, beanDefinition);
removeBeanDefinition() 其實也是呼叫 beanDefinitionMap.remove(beanName)。
對於類 GenericApplicationContext ,檢視原始碼你會發現他實現註冊、登出功能都是委託 DefaultListableBeanFactory 實現的。
所以 BeanDefinition 註冊並不是非常高大上的功能,內部就是用一個 Map 實現 ,並不是多麼高大上的騷操作,所以有時候我們會潛意識地認為某些技術很高大上就覺得他很深奧,如果試著去一探究竟你會發現,原來這麼簡單。雖然 BeanDefinitionRegistry 實現簡單,但是它作為 Spring IOC 容器的核心介面,其地位還是很重的。
知識星球