Spring 系列目錄(http://www.javashuo.com/article/p-kqecupyl-bm.html)html
在 Spring 中 Bean 有單例和多例之分,只有單例的 bean 纔會被 BeanFactory 管理,這個工做就是由 SingletonBeanRegistry 完成的。java
public interface SingletonBeanRegistry { void registerSingleton(String beanName, Object singletonObject); Object getSingleton(String beanName); boolean containsSingleton(String beanName); String[] getSingletonNames(); int getSingletonCount(); // 暴露全部的 singletonObjects 給外部 Object getSingletonMutex(); }
SingletonBeanRegistry 的默認實現爲 DefaultSingletonBeanRegistry,主要功能以下:spring
// 1. 建立 bean。先從緩存中獲取 bean,allowEarlyReference=true 時會嘗試從 singletonFactories 獲取提暴露的 bean // 緩存中沒有就調用 singletonFactory 方法建立 bean public Object getSingleton(String beanName); protected Object getSingleton(String beanName, boolean allowEarlyReference) public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory); // 2. 銷燬 bean。能夠銷燬所有的 bean,也能夠銷燬指定的 bean,最終都是調用 destroyBean 完成的。 // 銷燬 bean 以前須要先銷燬依賴它的全部 bean,再調用 bean.destroy() 銷燬本身 public void destroySingletons(); public void destroySingleton(String beanName); protected void destroyBean(String beanName, @Nullable DisposableBean bean);
(1) 與單例對象保存有關的四個集合緩存
咱們先從下面四個和單例有關的集合提及。前三個集合和 bean 的建立有關,其中 singletonObjects 保存已經建立成功的 bean 的集合,singletonFactories 和 earlySingletonObjects 屬於中間過程,一旦 bean 建立成功就會刪除對應的記錄,用於解決 bean 屬性注入過程當中的循環依賴的問題。最後一個用來保存當前全部已註冊的 bean。app
// 1.1 保存最終建立成功的單例 beanName -> beanInstance private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256); // 1.2 中間變量,beanName -> Objectfactory private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16); // 1.3 中間變量,bean 還在建立的時候就能夠獲取,用於檢測循環引用 private final Map<String, Object> earlySingletonObjects = new HashMap<>(16); // 2. 用來保存當前全部已註冊的 bean private final Set<String> registeredSingletons = new LinkedHashSet<>(256);
這裏涉及用於存儲 bean 的不一樣的 Map,可能讓人感到崩潰,簡單解釋以下:ide
singletonObjects
:用於保存 beanName 和建立 bean 實例之間的關係,beanName -> beanInstancesingletonfactories
:用於保存 beanname 和建立 bean 的工廠之間的關係,beanName -> ObjectfactoryearlySingletonObjects
:也是保存 beanName 和建立 bean 實例之間的關係,與 singletonObjects 的不一樣之處在於,當一個單例 bean 被放到這裏面後,那麼當 bean 還在建立過程當中,就能夠經過 getBean 方法獲取到了,其目的是用來檢測循環引用。registeredsingletons
:用來保存當前全部已註冊的 bean(2) 與單例對象建立有關的幾個屬性函數
// 1. 保存正在建立的 bean private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); // 2. 保存已經建立的 bean 集合,這樣進行依賴循環檢查時 // 若是已經 bean 在 inCreationCheckExclusions 中了,就不用再檢查 singletonsCurrentlyInCreation 了 private final Set<String> inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>(16)); // 3. 保存 bean 建立過程時的異常 private Set<Exception> suppressedExceptions;
(3) 與單例對象銷燬有關的四個集合ui
// 1. 一旦調用 destroySingletons() 銷燬全部的 bean 時就修改成 true private boolean singletonsCurrentlyInDestruction = false; // 2. 下面四個集合都和 bean 的銷燬有關 // 2.1 保存每一個 bean 的 destroy 方法 private final Map<String, Object> disposableBeans = new LinkedHashMap<>(); // 3.1 保存當前 bean 內的全部 bean 信息。containingBean -> containedBean // 當註冊 containedBeanMap 的同時也會註冊 dependentBeanMap 和 dependenciesForBeanMap private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16); // 3.2 保存依賴這個 bean 的全部 bean 的集合,依賴個人。containedBean -> containingBean // 因此銷燬這個 bean 的同時也要銷燬依賴它的全部 bean private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64); // 3.3 保存當前 bean 依賴的全部 bean 的集合,我依賴的。containingBean -> containedBean // 因此銷燬這個 bean 只要清空對應的記錄便可,而不會銷燬該 bean 依賴的其它 bean private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
@Override public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException { synchronized (this.singletonObjects) { Object oldObject = this.singletonObjects.get(beanName); if (oldObject != null) { throw new IllegalStateException(); } addSingleton(beanName, singletonObject); } } // 這個方法只有在本類中才調用,bean 屬性注入完成,直接添加 singletonObject protected void addSingleton(String beanName, Object singletonObject) { synchronized (this.singletonObjects) { this.singletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } // AbstractAutowireCapableBeanFactory#doCreateBean 調用。註冊 singletonFactory protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) { synchronized (this.singletonObjects) { if (!this.singletonObjects.containsKey(beanName)) { this.singletonFactories.put(beanName, singletonFactory); this.earlySingletonObjects.remove(beanName); this.registeredSingletons.add(beanName); } } }
這個沒什麼可說的,主要是要理清這四個集合的功能。能夠看到有兩種方法註冊單例,這兩種狀況都會將 bean 註冊到 registeredSingletons 中:this
addSingleton(String beanName, Object singletonObject)
將其註冊到 singletonObjects 中,這段代碼的邏輯見 getSingleton(String beanName, ObjectFactory<?> singletonFactory)
方法。DefaultSingletonBeanRegistry 不只管理了 bean 的註冊,還管理 bean 的生命週期,包括 bean 的建立和銷燬。code
Spring 中單例只會被建立一次,後續再獲取 bean 直接從單例緩存中獲取。
getSingleton(beanName)
直接從緩存中獲取 bean,也能夠指定是否查找提早暴露的 bean(也就是正在建立的 bean)。allowEarlyReference=true 時會查找正在建立的 bean。getSingleton(beanName, singletonFactory)
方法建立單例 bean。由於建立的時候會存在依賴注入的狀況,爲了解決可能存在的循環依賴問題,Spring 建立 bean 的原則是不等 bean 建立完成就會將建立 bean 的 ObjectFactory 提前曝光加入到緩存中,這樣經過 getSingleton(beanName, true)
就能夠在緩存中直接查找到這個 bean 的 ObjectFactory。public Object getSingleton(String beanName) { // 參數 true 設置標識容許時期依賴 return getSingleton(beanName, true); } protected Object getSingleton(String beanName, boolean allowEarlyReference) { // 1. 在已經建立完成的 singletonObjects 集合中查找 Object singletonObject = this.singletonObjects.get(beanName); // 2. 若是這個 bean 正在建立,則繼續嘗試從 earlySingletonObjects 中查找 if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) { synchronized (this.singletonObjects) { singletonObject = this.earlySingletonObjects.get(beanName); if (singletonObject == null && allowEarlyReference) { // 3. 當某些方法須要提早初始化的時候則會調用 addSingletonFactory 方法 // 將對應的 ObjectFactory 初始化策略存儲在 singletonFactories ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName); if (singletonFactory != null) { // 調用預先設定的 getObject 方法 singletonObject = singletonFactory.getObject(); // 記錄在緩存中,earlySingletonObjects 與 singletonFactories 互斥 this.earlySingletonObjects.put(beanName, singletonObject); this.singletonFactories.remove(beanName); } } } } return (singletonObject != NULL_OBJECT ? singletonObject : null); }
這個方法步驟以下:
而對於後續的全部內存操做都只爲了循環依賴檢測時候使用,也就是在 allowEarlyReference=true 的狀況下才會使用。
上面講解了從緩存中獲取單例的過程,那麼,若是緩存中不存在已經加載的單例 bean 就須要從頭開始 bean 的加載過程了,而 Spring 中使用 getSingleton 的重載方法 getSingleton(beanName, singletonFactory) 實現 bean 的加載過程。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) { Assert.notNull(beanName, "'beanName' must not be null"); synchronized (this.singletonObjects) { // 1. 首先檢查對應的 bean 是否已經加載過 // 由於 singleton 模式其實就是複用已建立的 bean,因此這一步是必須的 Object singletonObject = this.singletonObjects.get(beanName); // 2. 進行 singleton 的 bean 的初始化 if (singletonObject == null) { // 2.1 容器正在銷燬拋出異常 if (this.singletonsCurrentlyInDestruction) { throw new BeanCreationNotAllowedException(beanName); } // 2.2 將這個 bean 添加到 singletonsCurrentlyInCreation 集合中,這樣就能夠判斷 bean 是否存在建立 beforeSingletonCreation(beanName); boolean newSingleton = false; boolean recordSuppressedExceptions = (this.suppressedExceptions == null); if (recordSuppressedExceptions) { this.suppressedExceptions = new LinkedHashSet<Exception>(); } try { // 2.3 初始化 bean,委託給 ObjectFactory 完成 singletonObject = singletonFactory.getObject(); newSingleton = true; } catch (IllegalStateException ex) { // 2.4 ????????? singletonObject = this.singletonObjects.get(beanName); if (singletonObject == null) { throw ex; } } catch (BeanCreationException ex) { if (recordSuppressedExceptions) { for (Exception suppressedException : this.suppressedExceptions) { ex.addRelatedCause(suppressedException); } } throw ex; } finally { if (recordSuppressedExceptions) { this.suppressedExceptions = null; } // 2.5 從 singletonsCurrentlyInCreation 移除該 bean afterSingletonCreation(beanName); } if (newSingleton) { // 2.6 建立成功,加入緩存 addSingleton(beanName, singletonObject); } } return (singletonObject != NULL_OBJECT ? singletonObject : null); } }
上述代碼中實際上是使用了回調方法,使得程序能夠在單例建立的先後作一些準備及處理操做,而真正的獲取單例 bean 的方法其實並非在此方法中實現的,其實現邏輯是在 ObjectFactory 類型的實例 singletonFactory 中實現的。而這些準備及處理操做包括以下內容:
(1) 檢查緩存是否已經加載過
(2) 若沒有加載,則記錄 beanName 的正在加載狀態。
(3) 加載單例前記錄加載狀態。可能你會以爲 beforeSingletonCreation 方法是個空實現,裏面沒有任何邏輯,但其實不是,這個函數中作了一個很重要的操做:記錄加載狀態,也就是經過 this.singletonsCurrentlyInCreation.add(beanName) 將當前正要建立的 bean 記錄在緩存中,這樣即可以對循環依賴進行檢測。
protected void beforeSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) { throw new BeanCurrentlyInCreationException(beanName); } }
(4) 經過調用參數傳入的 ObjectFactory 的個體 Object 方法實例化 bean
(5) 加載單例後的處理方法調用。同步驟 (3) 的記錄加載狀態類似,當 bean加載結東後須要移除緩存中對該 bean 的正在加載狀態的記錄。
protected void afterSingletonCreation(String beanName) { if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) { throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation"); } }
(6) 將結果記錄至緩存並刪除加載 bean 過程當中所記錄的各類輔助狀態。
在建立 bean 的過程當中,不少工做都交給 ObjectFactory 這個工廠類完成,那它究竟是什麼呢?
public interface ObjectFactory<T> { T getObject() throws BeansException; }
在方法 getSingleton(beanName, singletonFactory)
和 addSingletonFactory(beanName, singletonFactory)
兩種都用到了 ObjectFactory,這兩處的 ObjectFactory 功能並非同樣的。 前者的 ObjectFactory 是用於建立 bean,屬於建立型 ObjectFactory,然後者只是簡單的持有 bean,屬於引用型 ObjectFactory,保存在 singletonFactories 集合中用於解決循環依賴的問題。
(1) 建立型 ObjectFactory
protected <T> T doGetBean(final String name, @Nullable final Class<T> requiredType, @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException { sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() { @Override public Object getObject() throws BeansException { try { return createBean(beanName, mbd, args); } catch (BeansException ex) { destroySingleton(beanName); throw ex; } } }); }
(2) 引用型 ObjectFactory
在 createBean 建立 bean 的過程當中,在實例化 bean 後就會將這個 bean 提早暴露出來,這樣就能夠提早在緩存中拿到正在建立的 bean。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args) { // 1. 反射建立 bean BeanWrapper instanceWrapper = null; if (instanceWrapper == null) { instanceWrapper = createBeanInstance(beanName, mbd, args); } final Object bean = instanceWrapper.getWrappedInstance(); // 2. 將這個 bean 經過 addSingletonFactory 暴露到緩存中,這樣指定 allowEarlyReference=true 就能夠提早查找到 boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences && isSingletonCurrentlyInCreation(beanName)); if (earlySingletonExposure) { // getEarlyBeanReference 默認直接將這個 bean 返回了 addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean)); } // 3. 以後再進行屬性注入和初始化等操做 Object exposedObject = bean; populateBean(beanName, mbd, instanceWrapper); exposedObject = initializeBean(beanName, exposedObject, mbd); }
bean 進行循環依賴檢查與兩個集合有關:
inCreationCheckExclusions
若是 bean 建立完成則添加到該集合中,這樣若是包含要檢查的 bean 就不用再檢查 singletonsCurrentlyInCreation 了。singletonsCurrentlyInCreation
bean 建立開始時先添加到這個集合中,建立成功後刪除// 若是 inCreation=false 則說明對象已經建立成功,直接添加到 inCreationCheckExclusions 集合中,不然就刪除 // 這樣在進行循環依賴檢查時,當這個集合包含該 bean 時就不用檢查 singletonsCurrentlyInCreation public void setCurrentlyInCreation(String beanName, boolean inCreation) { Assert.notNull(beanName, "Bean name must not be null"); if (!inCreation) { this.inCreationCheckExclusions.add(beanName); } else { this.inCreationCheckExclusions.remove(beanName); } } // isCurrentlyInCreation 和 isSingletonCurrentlyInCreation 區別仍是沒看明白??? public boolean isCurrentlyInCreation(String beanName) { Assert.notNull(beanName, "Bean name must not be null"); return (!this.inCreationCheckExclusions.contains(beanName) && isActuallyInCreation(beanName)); } // isActuallyInCreation 方法只有在 isCurrentlyInCreation 中調用,不明白爲何還要單獨抽出來 protected boolean isActuallyInCreation(String beanName) { return isSingletonCurrentlyInCreation(beanName); } public boolean isSingletonCurrentlyInCreation(String beanName) { return this.singletonsCurrentlyInCreation.contains(beanName); }
bean 建立成功後須要註冊 bean 以前的依賴關係,這樣銷燬時才能將依賴它的 bean 也同時銷燬
(1) 註冊依賴
// 保存當前 bean 內的全部 bean。containingBeanName -> containedBeanName public void registerContainedBean(String containedBeanName, String containingBeanName) { synchronized (this.containedBeanMap) { Set<String> containedBeans = this.containedBeanMap.computeIfAbsent(containingBeanName, k -> new LinkedHashSet<>(8)); if (!containedBeans.add(containedBeanName)) { return; } } registerDependentBean(containedBeanName, containingBeanName); } // dependentBeans 保存依賴個人全部 bean。containedBeanName -> containingBeanName // dependenciesForBeanMap 保存我依賴的全部 bean。containingBeanName -> containedBeanName public void registerDependentBean(String beanName, String dependentBeanName) { // 查找 bean 的註冊名稱 String canonicalName = canonicalName(beanName); synchronized (this.dependentBeanMap) { // jdk8 若是 key 不存在設置 value,不然返回 oldValue Set<String> dependentBeans = this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8)); // 若是已經註冊直接返回 if (!dependentBeans.add(dependentBeanName)) { return; } } synchronized (this.dependenciesForBeanMap) { Set<String> dependenciesForBean = this.dependenciesForBeanMap.computeIfAbsent(dependentBeanName, k -> new LinkedHashSet<>(8)); dependenciesForBean.add(canonicalName); } }
固然若是這個 bean 有銷燬方法,也會註冊其 DisposableBean
public void registerDisposableBean(String beanName, DisposableBean bean) { synchronized (this.disposableBeans) { this.disposableBeans.put(beanName, bean); } }
(2) 依賴查找
isDependent
查找兩個 bean 的依賴關係getDependentBeans
查找依賴這個 bean 的全部 beangetDependenciesForBean
查找這個 bean 依賴的全部 beanisDependent 查找兩個 bean 的依賴關係。若是 dependentBeanName 依賴 beanName 則返回 true,這其中會存在間接依賴的狀況,如 beanA -> beanB -> beanC,查詢 beanA -> beanC 的關係。
protected boolean isDependent(String beanName, String dependentBeanName) { synchronized (this.dependentBeanMap) { return isDependent(beanName, dependentBeanName, null); } } private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) { // 1. alreadySeen 是已經查找過的 bean,這裏面的 bean 都不存在依賴關係,若是存在則已經返回 true 了 if (alreadySeen != null && alreadySeen.contains(beanName)) { return false; } // 2. 獲取 bean 的註冊名稱 String canonicalName = canonicalName(beanName); // 3. 查找依賴 beanName 的全部 bean,若是有則確定有依賴,不然還要查找間接依賴 Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName); if (dependentBeans == null) { return false; } if (dependentBeans.contains(dependentBeanName)) { return true; } // 4. 逐個查找間接依賴 for (String transitiveDependency : dependentBeans) { if (alreadySeen == null) { alreadySeen = new HashSet<>(); } alreadySeen.add(beanName); if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) { return true; } } return false; }
// 銷燬全部 bean public void destroySingletons() { synchronized (this.singletonObjects) { this.singletonsCurrentlyInDestruction = true; } String[] disposableBeanNames; synchronized (this.disposableBeans) { disposableBeanNames = StringUtils.toStringArray(this.disposableBeans.keySet()); } for (int i = disposableBeanNames.length - 1; i >= 0; i--) { destroySingleton(disposableBeanNames[i]); } this.containedBeanMap.clear(); this.dependentBeanMap.clear(); this.dependenciesForBeanMap.clear(); clearSingletonCache(); } // 銷燬指定的 bean public void destroySingleton(String beanName) { removeSingleton(beanName); DisposableBean disposableBean; synchronized (this.disposableBeans) { disposableBean = (DisposableBean) this.disposableBeans.remove(beanName); } destroyBean(beanName, disposableBean); }
真正的銷燬在 destroyBean 中完成。
protected void destroyBean(String beanName, @Nullable DisposableBean bean) { // 1. 首先將依賴這個 beanName 的所有銷燬 Set<String> dependencies; // ConcurrentHashMap 爲何還須要同步??? synchronized (this.dependentBeanMap) { dependencies = this.dependentBeanMap.remove(beanName); } if (dependencies != null) { for (String dependentBeanName : dependencies) { destroySingleton(dependentBeanName); } } // 2. 真正銷燬該 beanName if (bean != null) { bean.destroy(); } // 3. 銷燬 containedBeans Set<String> containedBeans; synchronized (this.containedBeanMap) { containedBeans = this.containedBeanMap.remove(beanName); } if (containedBeans != null) { for (String containedBeanName : containedBeans) { destroySingleton(containedBeanName); } } // 4. 清理 dependentBeanMap 中殘存的 beanName 記錄 synchronized (this.dependentBeanMap) { for (Iterator<Map.Entry<String, Set<String>>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) { Map.Entry<String, Set<String>> entry = it.next(); Set<String> dependenciesToClean = entry.getValue(); dependenciesToClean.remove(beanName); if (dependenciesToClean.isEmpty()) { it.remove(); } } } // 5. 清理 dependenciesForBeanMap this.dependenciesForBeanMap.remove(beanName); }
天天用心記錄一點點。內容也許不重要,但習慣很重要!