上篇文章咱們對 BeanDefinition 進行了討論,BeanDefinition 是對 Bean 的定義,其保存了 Bean 的各類信息,如屬性、構造方法參數、是否單例、是否延遲加載等。這裏的註冊 Bean 是指將 Bean 定義成 BeanDefinition,以後放入 Spring 容器中,咱們常說的容器其實就是 Beanfactory 中的一個 Map,key 是 Bean 的名稱,value 是 Bean 對應的 BeanDefinition,這個註冊 Bean 的方法由 BeanFactory 子類實現。java
注:本篇文章使用的 SpringBoot 版本爲 2.0.3.RELEASE,其 Spring 版本爲 5.0.7.RELEASE緩存
在前面的《Spring(三)核心容器 - ApplicationContext 上下文啓動準備》文章中說過,當前環境的 BeanFactory 實現類是 DefaultListableBeanFactory,是一個具備註冊功能的完整 Bean 工廠,註冊 Bean 的方法是 registerBeanDefinition,DefaultListableBeanFactory 經過實現 BeanDefinitionRegistry 接口,重寫該方法。ide
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { ... @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { ... } ... }
討論 registerBeanDefinition 方法以前,先來簡單介紹 BeanDefinitionRegistry 接口。ui
BeanDefinitionRegistry 是一個接口,它定義了關於 BeanDefinition 的註冊、移除、查詢等一系列的操做。this
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; // 根據 beanName 判斷容器是否存在對應的 BeanDefinition boolean containsBeanDefinition(String beanName); // 獲取全部的 BeanDefinition String[] getBeanDefinitionNames(); // 獲取 BeanDefinition 數量 int getBeanDefinitionCount(); // 判斷 beanName 是否被佔用 boolean isBeanNameInUse(String beanName); }
該接口有三個實現類:DefaultListableBeanFactory、GenericApplicationContext、SimpleBeanDefinitionRegistry,其中 GenericApplicationContext 底層調用的是 DefaultListableBeanFactory 中的實現方法,因此嚴格意義上來講,只有兩個實現類。這裏,咱們主要討論 DefaultListableBeanFactory 中的方法實現。debug
前面說過 registerBeanDefinition 方法的主要實現類是 DefaultListableBeanFactory :代理
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable { ... // 存儲全部的 BeanDefinition ,key 是 Bean 的名稱。咱們一直稱呼的容器,底層就是這個 Map private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256); // 存儲全部 Bean 名稱 private volatile List<String> beanDefinitionNames = new ArrayList<>(256); // 存儲手動註冊的單例 Bean 名稱 private volatile Set<String> manualSingletonNames = new LinkedHashSet<>(16); // 存儲凍結的 BeanDefinition,留做後面緩存用 private volatile String[] frozenBeanDefinitionNames; ... // 方法的入參爲 Bean 名稱和對應的 BeanDefinition @Override public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException { Assert.hasText(beanName, "Bean name must not be empty"); Assert.notNull(beanDefinition, "BeanDefinition must not be null"); // 若是 beanDefinition 的實例爲 AbstractBeanDefinition,則進行驗證 if (beanDefinition instanceof AbstractBeanDefinition) { try { // 驗證: // 若是有重寫方法,可是是工廠方法,則拋出異常,由於重寫方法須要代理,而工廠方法沒法代理; // 經過方法名稱,判斷 Bean 中該名稱方法存在的數量,0:方法不存在,報錯;1:方法非重載,overloaded 屬性設爲 false; ((AbstractBeanDefinition) beanDefinition).validate(); } catch (BeanDefinitionValidationException ex) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Validation of bean definition failed", ex); } } BeanDefinition oldBeanDefinition; // 先從 beanDefinitionMap 中嘗試獲取 beanName 對應 BeanDefinition oldBeanDefinition = this.beanDefinitionMap.get(beanName); // 不爲 null,則 beanName 對應的 BeanDefinition 已經存在 if (oldBeanDefinition != null) { // 是否應容許覆蓋 BeanDefinition,不容許則拋異常 if (!isAllowBeanDefinitionOverriding()) { throw new BeanDefinitionStoreException(beanDefinition.getResourceDescription(), beanName, "Cannot register bean definition [" + beanDefinition + "] for bean '" + beanName + "': There is already [" + oldBeanDefinition + "] bound."); } /***************************** 若容許覆蓋 *****************************/ // 判斷 Bean 的角色大小: // 0:用戶定義的 Bean、1:來源於配置文件的 Bean、2:Spring 內部的 Bean; // 當原 BeanDefinition 角色小於新的 BeanDefinition 角色時,輸出一個 warn 日誌,提示 BeanDefinition 被覆蓋 else if (oldBeanDefinition.getRole() < beanDefinition.getRole()) { // e.g. was ROLE_APPLICATION, now overriding with ROLE_SUPPORT or ROLE_INFRASTRUCTURE if (this.logger.isWarnEnabled()) { this.logger.warn("Overriding user-defined bean definition for bean '" + beanName + "' with a framework-generated bean definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } // 當新 BeanDefinition 屬性值不等於原 BeanDefinition 屬性值時,輸出 info 提示信息 else if (!beanDefinition.equals(oldBeanDefinition)) { if (this.logger.isInfoEnabled()) { this.logger.info("Overriding bean definition for bean '" + beanName + "' with a different definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } // 最後,輸出 debug 日誌信息:用等效的新 BeanDefinition 覆蓋原 BeanDefinition else { if (this.logger.isDebugEnabled()) { this.logger.debug("Overriding bean definition for bean '" + beanName + "' with an equivalent definition: replacing [" + oldBeanDefinition + "] with [" + beanDefinition + "]"); } } // 添加至 BeanDefinition 集合,並覆蓋原 BeanDefinition this.beanDefinitionMap.put(beanName, beanDefinition); } // Map 中無對應的 BeanDefinition,則直接註冊 else { // 已開始建立 Bean if (hasBeanCreationStarted()) { synchronized (this.beanDefinitionMap) { // 將 Bean 對應的 BeanDefinition 放入 beanDefinitionMap 中 this.beanDefinitionMap.put(beanName, beanDefinition); // 建立新的 beanNames 集合,並將已緩存的 beanName 和新的 beanName 加入該集合 List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1); updatedDefinitions.addAll(this.beanDefinitionNames); updatedDefinitions.add(beanName); this.beanDefinitionNames = updatedDefinitions; // 在手動註冊 Bean 的集合中,若是存在同名的 beanName,則將集合中同名的 beanName 刪除 if (this.manualSingletonNames.contains(beanName)) { Set<String> updatedSingletons = new LinkedHashSet<>(this.manualSingletonNames); updatedSingletons.remove(beanName); this.manualSingletonNames = updatedSingletons; } } } // 仍處於啓動註冊階段 else { // 將當前 Bean 對應的 BeanDefinition 放入 beanDefinitionMap 中 this.beanDefinitionMap.put(beanName, beanDefinition); // 將當前 beanName 放入 beanDefinitionNames this.beanDefinitionNames.add(beanName); // 刪除手動註冊 Bean 集合中同名的 beanName this.manualSingletonNames.remove(beanName); } // 將存儲凍結 BeanDefinition 的 Map 置爲 null this.frozenBeanDefinitionNames = null; } // 當前註冊的 BeanDefinition 已在 beanDefinitionMap 中存在,或者其實例已在存儲單例 Bean 的 Map 中存在 if (oldBeanDefinition != null || containsSingleton(beanName)) { // 重置 BeanDefinition,主要作一些清理工做 resetBeanDefinition(beanName); } } }
執行完 registerBeanDefinition 方法後,Bean 的名稱和對應的 BeanDefinition 就被放入了容器中,後續獲取 Bean 也是從這個容器中獲取。日誌
固然,DefaultListableBeanFactory 還實現了 BeanDefinitionRegistry 接口的其它方法,如對 BeanDefinition 進行移除、判斷是否存在、獲取數量等操做,其實都是圍繞 beanDefinitionMap 這個 Map 進行的,這裏就不詳細介紹。code
須要注意的是 registerBeanDefinition 方法會在後面頻繁被調用,後續會逐一提到。
這篇文章主要對註冊 Bean 的核心方法進行討論,但其中涉及到了單例 Bean 實例註冊,這和當前文章的註冊 Bean 不一樣,當前保存的是任意 Bean 的信息,然後者,保存的是單例 Bean 的對象,咱們將在下篇文章詳細討論。