17-DefaultSingletonBeanRegistry

背景簡(jiǎn)介

出現(xiàn)的原因

我們上面介紹了:

  • AliasRegistrySimpleAliasRegistry他們分別定義和實(shí)現(xiàn)了對(duì)別名管理的支持
  • SingletonBeanRegistry定義了對(duì)單例 Bean 管理的支持

按照我們之前對(duì) Spring 整合不通接口功能的套路的介紹,現(xiàn)在該有個(gè)類(lèi)來(lái)繼承SimpleAliasRegistry同時(shí)實(shí)現(xiàn)SingletonBeanRegistry接口吁朦,從而實(shí)現(xiàn)將"對(duì)單例 Bean的管理”幔欧、“對(duì)別名的管理”兩個(gè)功能的整合涝焙。

職責(zé)

將"對(duì)單例 Bean的管理”俺亮、“對(duì)別名的管理”兩個(gè)功能整合。

注意點(diǎn)

思路很簡(jiǎn)單术吝,主要關(guān)注它里面的實(shí)例屬性都有什么意義弄痹。這在后面的解決循環(huán)依賴(lài)、進(jìn)行 bean 回收中都有幫助嘹悼。

源碼

繼承關(guān)系

1.png

實(shí)例屬性介紹

因?yàn)?code>DefaultSingletonBeanRegistry通過(guò)繼承SimpleAliasRegistry直接擁有了對(duì)別名的管理功能叛甫,所以在DefaultSingletonBeanRegistry中只需要將SingletonBeanRegistry的相關(guān)功能支持一遍即可。

/**
 * Cache of singleton objects: bean name --> bean instance
 * 正經(jīng)的單例 bean 實(shí)例緩存杨伙,里面放的都是構(gòu)造其监、屬性填充完成、初始化好的限匣。
 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/**
 * Cache of singleton factories: bean name --> ObjectFactory
 * 單例 bean 工廠的緩存抖苦,用于實(shí)現(xiàn)懶加載,需要時(shí)就拿出來(lái)米死,用 ObjectFactory 創(chuàng)建 Bean 實(shí)例并放到
 * earlySingletonObjects 等待屬性填充和初始化
 */
private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);

/**
 * Cache of early singleton objects: bean name --> bean instance
 * 用于提前暴露 Bean 實(shí)例的地址锌历,用于解決單例 bean 的循環(huán)依賴(lài)問(wèn)題,這里面的東西都未執(zhí)行屬性填充和初始化
 */
private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);

/**
 * Set of registered singletons, containing the bean names in registration order
 * 注冊(cè)的單例 Bean 的id集合哲身,等價(jià)于 singletonObjects.keySet()
 */
//TODO 沒(méi)必要專(zhuān)門(mén)用個(gè)集合來(lái)存儲(chǔ)辩涝,這樣維護(hù)一致性要花費(fèi)不少精力
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

/**
 * 當(dāng)前正在創(chuàng)建中的 Bean ,在提供的擴(kuò)展方法——“通過(guò)一個(gè)具有創(chuàng)造實(shí)例勘天、填充屬性怔揩、初始化功能的工廠方法
 * 直接獲得最終單例Bean”中用作記錄
 * 
 */
private final Set<String> singletonsCurrentlyInCreation =
        Collections.newSetFromMap(new ConcurrentHashMap<>(16));

/**
 * 要排除創(chuàng)建標(biāo)記的Bean
 */
private final Set<String> inCreationCheckExclusions =
        Collections.newSetFromMap(new ConcurrentHashMap<>(16));
/**
 * Disposable bean instances: bean name --> disposable instance
 */
// 這里面的bean有刪除的鉤子,在刪除 bean 時(shí)脯丝,從注冊(cè)中刪除后需要調(diào)用這里的方法 
// 這里的 disposableBeans 的 key 和要回收的 bean 實(shí)例在 singletonObjects 中的 key 一樣
private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
/**
 * Map between containing bean names: bean name --> Set of bean names that the bean contains
 */
// key 對(duì)應(yīng)的 bean 里面有變量是用的 value 中的 bean
private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);
/**
 * Map between dependent bean names: bean name --> Set of dependent bean names
 */
// key 對(duì)應(yīng)的 bean 被 value 中的 bean 依賴(lài)商膊,也就是說(shuō) value 中的 bean 銷(xiāo)毀完 ,key 對(duì)應(yīng)的 bean 才能開(kāi)始銷(xiāo)毀
private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
/**
 * Map between depending bean names: bean name --> Set of bean names for the bean's dependencies
 */
// key 對(duì)應(yīng)的 bean 依賴(lài)了 value 中的 bean宠进,也就是說(shuō) key 對(duì)應(yīng)的 bean 銷(xiāo)毀完晕拆,value 中的 bean 才能銷(xiāo)毀
private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
/**
 * List of suppressed Exceptions, available for associating related causes
 */
@Nullable
private Set<Exception> suppressedExceptions;
/**
 * 標(biāo)記值,如果在銷(xiāo)毀階段,不允許新注冊(cè)單例 Bean
 */
private boolean singletonsCurrentlyInDestruction = false;

實(shí)現(xiàn)的接口方法——增

// 將 Bean 實(shí)例注冊(cè)到 singletonObjects 中
@Override
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
    Assert.notNull(beanName, "Bean name must not be null");
    Assert.notNull(singletonObject, "Singleton object must not be null");
    synchronized (this.singletonObjects) {
        Object oldObject = this.singletonObjects.get(beanName);
        if (oldObject != null) {
            throw new IllegalStateException("Could not register object [" + singletonObject +
                    "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
        }
        addSingleton(beanName, singletonObject);
    }
}

/**
 * Add the given singleton object to the singleton cache of this factory.
 * <p>To be called for eager registration of singletons.
 *
 * @param beanName        the name of the bean
 * @param singletonObject the singleton object
 */
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);
    }
}

實(shí)現(xiàn)的接口方法——查

@Override
@Nullable
// 根據(jù) bean 的 name(這里指的是 ID 实幕,不是 alias )獲得對(duì)應(yīng)的 bean 實(shí)例
public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}

/**
 * 返回 id 對(duì)應(yīng)的實(shí)例吝镣,可能是正經(jīng)的實(shí)例,也可能是為了解決循環(huán)依賴(lài)提前暴露出的實(shí)例地址
 * 可以通過(guò)入?yún)⒖刂剖欠裨跊](méi)有得到實(shí)例的情況下提前創(chuàng)造實(shí)例返回地址
 *
 * @param beanName            the name of the bean to look for
 * @param allowEarlyReference 是否創(chuàng)造提前暴露的實(shí)例地址
 * @return the registered singleton object, or {@code null} if none found
 */
@Nullable
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    Object singletonObject = this.singletonObjects.get(beanName); // 先看正經(jīng)緩存中有沒(méi)有弄好的
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
    // 沒(méi)拿到昆庇,而且正在通過(guò)擴(kuò)展的工廠方法進(jìn)行獲取最終實(shí)例屬性
        synchronized (this.singletonObjects) {
            singletonObject = this.earlySingletonObjects.get(beanName); // 看工廠方法有沒(méi)有提前丟到這里
            if (singletonObject == null && allowEarlyReference) {// 沒(méi)有丟這里末贾,看看我們給他創(chuàng)建個(gè)實(shí)例
                ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
                if (singletonFactory != null) {// 有創(chuàng)建實(shí)例的工廠,就搞一下
                    singletonObject = singletonFactory.getObject();
                    this.earlySingletonObjects.put(beanName, singletonObject);
                    this.singletonFactories.remove(beanName);
                }
            }
        }
    }
    return singletonObject;
}

/**
 * 正在通過(guò)外部工廠方法進(jìn)行從頭到尾的創(chuàng)建
 * @param beanName the name of the bean
 */
public boolean isSingletonCurrentlyInCreation(String beanName) {
    return this.singletonsCurrentlyInCreation.contains(beanName);
}


/**
 * Exposes the singleton mutex to subclasses and external collaborators.
 * <p>Subclasses should synchronize on the given Object if they perform
 * any sort of extended singleton creation phase. In particular, subclasses
 * should <i>not</i> have their own mutexes involved in singleton creation,
 * to avoid the potential for deadlocks in lazy-init situations.
 */
public final Object getSingletonMutex() {
    return this.singletonObjects;
}

@Override
public boolean containsSingleton(String beanName) {
    return this.singletonObjects.containsKey(beanName);
}

@Override
public String[] getSingletonNames() {
    synchronized (this.singletonObjects) {
        return StringUtils.toStringArray(this.registeredSingletons);
    }
}

@Override
public int getSingletonCount() {
    synchronized (this.singletonObjects) {
        return this.registeredSingletons.size();
    }
}

擴(kuò)展方法——工廠懶加載功能【此工廠僅創(chuàng)建實(shí)例】

/**
 * 把用來(lái)創(chuàng)建 bean 實(shí)例的工廠方法保存至 singletonFactories 中
 * TODO : 注意了整吆,這個(gè) singletonFactory 僅創(chuàng)建實(shí)例拱撵,用來(lái)解決循環(huán)依賴(lài),不負(fù)責(zé)初始化表蝙、填充屬性什么的
 *
 * @param beanName         the name of the bean
 * @param singletonFactory the factory for the singleton object
 */
protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
  Assert.notNull(singletonFactory, "Singleton factory must not be null");
  synchronized (this.singletonObjects) {
    if (!this.singletonObjects.containsKey(beanName)) {
      this.singletonFactories.put(beanName, singletonFactory);
      this.earlySingletonObjects.remove(beanName);
      this.registeredSingletons.add(beanName);
    }
  }
}

擴(kuò)展方法——完全委托外部完成實(shí)例所有創(chuàng)建操作

/**
 * Return the (raw) singleton object registered under the given name,
 * creating and registering a new one if none registered yet.
 *
 * @param beanName         the name of the bean
 * @param singletonFactory the ObjectFactory to lazily create the singleton
 *                         with, if necessary
 * @return the registered singleton object
 */
// 創(chuàng)建 beanName 對(duì)應(yīng)的單例 bean 拴测,如果還沒(méi)創(chuàng)建就創(chuàng)建,創(chuàng)建過(guò)就直接返回府蛇,
//
// 第二個(gè)入?yún)⒉皇菓屑虞d集索,在這里是直接調(diào)用創(chuàng)建然后放到正經(jīng)緩存中去來(lái)。
// 使用表達(dá)式入?yún)⒌脑蛑豢赡苁欠奖阌脩?hù)自定義邏輯汇跨,包括使用閉包訪問(wèn)自定義變量什么的抄谐。
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    Assert.notNull(beanName, "Bean name must not be null");
    synchronized (this.singletonObjects) {
        Object singletonObject = this.singletonObjects.get(beanName);
        if (singletonObject == null) { // 緩存中沒(méi)有,說(shuō)明之前沒(méi)創(chuàng)建過(guò)扰法,那就創(chuàng)建一次
            if (this.singletonsCurrentlyInDestruction) { // 已經(jīng)進(jìn)入刪除階段,不允許創(chuàng)建
                throw new BeanCreationNotAllowedException(beanName,
                        "Singleton bean creation not allowed while singletons of this factory are in destruction " +
                                "(Do not request a bean from a BeanFactory in a destroy method implementation!)");
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Creating shared instance of singleton bean '" + beanName + "'");
            }
      // 創(chuàng)建前的緩存標(biāo)記——標(biāo)記此 beanName 正在使用外部方法創(chuàng)建中
            beforeSingletonCreation(beanName); 
            boolean newSingleton = false;
            boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
            if (recordSuppressedExceptions) {
                this.suppressedExceptions = new LinkedHashSet<>();
            }
            try {
                // 創(chuàng)建 bean 實(shí)例毅厚,并初始化塞颁。
                // 如果總?cè)纸嵌葋?lái)看的話(huà),其實(shí)這個(gè)里面的邏輯就是調(diào)用的 creatBean()
                singletonObject = singletonFactory.getObject();
                newSingleton = true;
            } catch (IllegalStateException ex) {
                // Has the singleton object implicitly appeared in the meantime ->
                // if yes, proceed with it since the exception indicates that state.
                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;
                }
        // 完成創(chuàng)建吸耿,刪除標(biāo)記——將此 beanName 從正在創(chuàng)建的列表中刪除
                afterSingletonCreation(beanName);
            }
            if (newSingleton) { // 緩存到正經(jīng)緩存單例的里面
                addSingleton(beanName, singletonObject);
            }
        }
        return singletonObject;
    }
}


protected void beforeSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
        throw new BeanCurrentlyInCreationException(beanName);
    }
}

protected void afterSingletonCreation(String beanName) {
    if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.remove(beanName)) {
        throw new IllegalStateException("Singleton '" + beanName + "' isn't currently in creation");
    }
}

擴(kuò)展方法——Bean 之間關(guān)系的管理

/**
 * Register a containment relationship between two beans,
 * e.g. between an inner bean and its containing outer bean.
 * <p>Also registers the containing bean as dependent on the contained bean
 * in terms of destruction order.
 *
 * @param containedBeanName  the name of the contained (inner) bean
 * @param containingBeanName the name of the containing (outer) bean
 * @see #registerDependentBean
 */
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);
}

/**
 * Register a dependent bean for the given bean,
 * to be destroyed before the given bean is destroyed.
 *
 * @param beanName          the name of the bean
 * @param dependentBeanName the name of the dependent bean
 */
public void registerDependentBean(String beanName, String dependentBeanName) {
    String canonicalName = canonicalName(beanName);

    synchronized (this.dependentBeanMap) {
        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);
    }
}

很容易理解祠锣,不在詳細(xì)介紹,我覺(jué)得看實(shí)例屬性介紹已經(jīng)夠了咽安。

擴(kuò)展方法——檢測(cè)依賴(lài)是否存在

這個(gè)方法常常用來(lái)檢測(cè)循環(huán)依賴(lài)的存在伴网,其實(shí) Spring 框架是做了針對(duì)單例 bean 的解決循環(huán)依賴(lài)的操作的:通過(guò)提前暴露地址解決依賴(lài)——這樣就不會(huì)輪到A—>B—>A時(shí)最后回頭創(chuàng)建 A,可以直接拿到A實(shí)例妆棒。

但是上面僅僅是解決屬性上的循環(huán)依賴(lài)澡腾,如果連實(shí)例都創(chuàng)建不出來(lái),這個(gè)循環(huán)依賴(lài)就沒(méi)法解決了糕珊,所以我們提供一個(gè)用來(lái)檢測(cè)依賴(lài)的工具函數(shù)還有有必要的:

擴(kuò)展:兩種導(dǎo)致無(wú)法創(chuàng)建實(shí)例的循環(huán)依賴(lài)

  1. dependOn动分,手動(dòng)配置,A dependOn B表明B要在A之前完整構(gòu)建完红选。這種依賴(lài)如果出現(xiàn)循環(huán)的話(huà)澜公,是一個(gè)實(shí)例都創(chuàng)建不出來(lái)的。
  2. 依賴(lài)的傳遞是用來(lái)創(chuàng)建實(shí)例的構(gòu)造函數(shù)入?yún)?/li>

另外喇肋,我們?cè)诮鉀Q循環(huán)依賴(lài)失敗時(shí)也要判斷影響范圍坟乾,所以也需要

/**
 * 檢測(cè)依賴(lài)
 *
 * @param beanName          the name of the bean to check
 * @param dependentBeanName the name of the dependent bean
 * @since 4.0
 */
protected boolean isDependent(String beanName, String dependentBeanName) {
    synchronized (this.dependentBeanMap) {
        return isDependent(beanName, dependentBeanName, null);
    }
}

// 從 dependentBeanMap 中找迹辐,看能否找到從 beanName-->dependentBeanName 的直接/間接映射
// 1. 遞歸
// 2. 樹(shù)的深度遍歷
// 思路很簡(jiǎn)單,和 SimpleAliasRegistry 的那個(gè)遍歷差不多
private boolean isDependent(String beanName, String dependentBeanName, @Nullable Set<String> alreadySeen) {
    if (alreadySeen != null && alreadySeen.contains(beanName)) {
        return false;
    }
    String canonicalName = canonicalName(beanName);
    Set<String> dependentBeans = this.dependentBeanMap.get(canonicalName);
    if (dependentBeans == null) {
        return false;
    }
    if (dependentBeans.contains(dependentBeanName)) {
        return true;
    }
    for (String transitiveDependency : dependentBeans) {
        if (alreadySeen == null) {
            alreadySeen = new HashSet<>();
        }
        alreadySeen.add(beanName);
        if (isDependent(transitiveDependency, dependentBeanName, alreadySeen)) {
            return true;
        }
    }
    return false;
}

/**
 * Determine whether a dependent bean has been registered for the given name.
 *
 * @param beanName the name of the bean to check
 */
// 判斷 beanName 是否被依賴(lài)
protected boolean hasDependentBean(String beanName) {
    return this.dependentBeanMap.containsKey(beanName);
}

/**
 * Return the names of all beans which depend on the specified bean, if any.
 *
 * @param beanName the name of the bean
 * @return the array of dependent bean names, or an empty array if none
 */
public String[] getDependentBeans(String beanName) {
    Set<String> dependentBeans = this.dependentBeanMap.get(beanName);
    if (dependentBeans == null) {
        return new String[0];
    }
    synchronized (this.dependentBeanMap) {
        return StringUtils.toStringArray(dependentBeans);
    }
}

擴(kuò)展方法——清除指定/所有單例 bean

public void destroySingletons() {
    if (logger.isDebugEnabled()) {
        logger.debug("Destroying singletons in " + this);
    }
    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();
}

/**
 * Clear all cached singleton instances in this registry.
 *
 * @since 4.3.15
 */
protected void clearSingletonCache() {
    synchronized (this.singletonObjects) {
        this.singletonObjects.clear();
        this.singletonFactories.clear();
        this.earlySingletonObjects.clear();
        this.registeredSingletons.clear();
        this.singletonsCurrentlyInDestruction = false;
    }
}

/**
 * Destroy the given bean. Delegates to {@code destroyBean}
 * if a corresponding disposable bean instance is found.
 *
 * @param beanName the name of the bean
 * @see #destroyBean
 */
// 這里可以?xún)?yōu)化吧甚侣,這里算作是樹(shù)形的遞歸調(diào)用明吩,最開(kāi)始調(diào)用起這個(gè)函數(shù)時(shí)也是用的循環(huán),
// 在方法頭加一個(gè)判斷渺绒,如果remove發(fā)現(xiàn)沒(méi)有贺喝,說(shuō)明在刪除其他單例時(shí)就提前刪完此單例bean了,直接退出
public void destroySingleton(String beanName) {
    // 此函數(shù)主要目的是取消單例和對(duì)應(yīng)的 DisposableBean 的注冊(cè)

    // Remove a registered singleton of the given name, if any.
    removeSingleton(beanName);

    // Destroy the corresponding DisposableBean instance.
    DisposableBean disposableBean;
    synchronized (this.disposableBeans) {
        disposableBean = (DisposableBean) this.disposableBeans.remove(beanName);
    }
    // 將具體的銷(xiāo)毀工作委托出去
    destroyBean(beanName, disposableBean);
}

/**
 * Destroy the given bean. Must destroy beans that depend on the given
 * bean before the bean itself. Should not throw any exceptions.
 *
 * @param beanName the name of the bean
 * @param bean     the bean instance to destroy
 */
protected void destroyBean(String beanName, @Nullable DisposableBean bean) {
    // 先將依賴(lài) beanName 的單例銷(xiāo)毀才能銷(xiāo)毀 beanName

    // Trigger destruction of dependent beans first...
    Set<String> dependencies;
    synchronized (this.dependentBeanMap) {
        // Within full synchronization in order to guarantee a disconnected Set
        dependencies = this.dependentBeanMap.remove(beanName);
    }
    if (dependencies != null) {
        if (logger.isDebugEnabled()) {
            logger.debug("Retrieved dependent beans for bean '" + beanName + "': " + dependencies);
        }
        for (String dependentBeanName : dependencies) { // 先遞歸銷(xiāo)毀依賴(lài) beanName 的單例
            destroySingleton(dependentBeanName);
        }
    }
    // 完成依賴(lài)此單例的項(xiàng)目的銷(xiāo)毀

    // Actually destroy the bean now...
    if (bean != null) {
        try {
            bean.destroy(); // 銷(xiāo)毀 beanName
        } catch (Throwable ex) {
            logger.error("Destroy method on bean with name '" + beanName + "' threw an exception", ex);
        }
    }

    // 將包含此單例的項(xiàng)目進(jìn)行銷(xiāo)毀
    // TODO 感覺(jué)怪怪的宗兼,銷(xiāo)毀完 beanName 后 containedBeans 應(yīng)該不能繼續(xù)工作了躏鱼,怎么能把這個(gè)放在最后面?
    // Trigger destruction of contained beans...
    Set<String> containedBeans;
    synchronized (this.containedBeanMap) {
        // Within full synchronization in order to guarantee a disconnected Set
        containedBeans = this.containedBeanMap.remove(beanName);
    }
    if (containedBeans != null) {
        for (String containedBeanName : containedBeans) {
            destroySingleton(containedBeanName);
        }
    }

    // 完成包含此單例的項(xiàng)目的銷(xiāo)毀

    // 做一些善后操作殷绍,beanName 依賴(lài)了一些 bean 染苛,把這些映射移除即可

    // Remove destroyed bean from other beans' dependencies.
    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();
            }
        }
    }

    // Remove destroyed bean's prepared dependency information.
    this.dependenciesForBeanMap.remove(beanName);
}

總結(jié)記錄

此類(lèi)主要關(guān)注那些實(shí)例屬性即可,把那些Map的功能梳理清楚主到,方法都是見(jiàn)名知意的茶行。

問(wèn)題

冗余數(shù)據(jù)結(jié)構(gòu)定義問(wèn)題

我們?cè)诮榻B上面的實(shí)例屬性時(shí)很容易發(fā)現(xiàn):我們定義的Map,Set那一大串雖然很多很全,但是有點(diǎn)過(guò)多了登钥,很多屬性我們?nèi)绻屑?xì)品味的話(huà)還是有問(wèn)題的——有的屬性我們覺(jué)得一樣畔师,實(shí)際上可能真的有點(diǎn)冗余;有的屬性我們覺(jué)得一樣牧牢,但是他們的職能看锉、使用場(chǎng)景完全不同。

singletonObjectsregisteredSingletons

/**
 * Cache of singleton objects: bean name --> bean instance
 */
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

/**
 * Set of registered singletons, containing the bean names in registration order
 */
//TODO 沒(méi)必要專(zhuān)門(mén)用個(gè)集合來(lái)存儲(chǔ)塔鳍,這樣維護(hù)一致性要花費(fèi)不少精力
private final Set<String> registeredSingletons = new LinkedHashSet<>(256);

個(gè)人認(rèn)為沒(méi)必要專(zhuān)門(mén)創(chuàng)建下面的Set直接用singletonObjects.keySet足以伯铣,原因:

  1. registeredSingletons為私有且未向外暴露,不會(huì)出現(xiàn)線(xiàn)程安全之類(lèi)的其他的的情況轮纫,不會(huì)拖singletonObjects的后腿
  2. 線(xiàn)程的集合類(lèi)接口腔寡,沒(méi)有理由不用

Bean 銷(xiāo)毀的順序問(wèn)題

destroyBean中,銷(xiāo)毀的先后順序是:

  1. 依賴(lài)此beanNamebean
  2. beanName對(duì)應(yīng)的bean
  3. 包含此beanName的外部容器

個(gè)人感覺(jué)應(yīng)該是3,1,2/1,3,2而不是123掌唾。

先銷(xiāo)毀了 beanName對(duì)應(yīng)bean放前,外面的容器就無(wú)法正常工作了,會(huì)造成請(qǐng)求失敗郑兴。

擴(kuò)展

冗余數(shù)據(jù)結(jié)構(gòu)定義問(wèn)題

dependentBeanMapdependenciesForBeanMap

理論上說(shuō)吧你用邏輯運(yùn)算也是能算出來(lái)這兩個(gè)是有邏輯重復(fù)的犀斋。但是如果合并成一個(gè)數(shù)據(jù)結(jié)構(gòu)的話(huà),那就是一個(gè)圖了情连,可能要用一個(gè)二維矩陣來(lái)表示叽粹,這需要專(zhuān)門(mén)封裝很多東西。而且,你獲得一個(gè)依賴(lài)集虫几,遍歷那么多锤灿,有點(diǎn)復(fù)雜了吧。

綜上辆脸,個(gè)人認(rèn)為這個(gè)不能隨便替代但校。

singletonsCurrentlyInCreationearlySingletonObjectssingletonFactories

singletonsCurrentlyInCreation這個(gè)鉤子是專(zhuān)門(mén)為擴(kuò)展方法中的那個(gè)將 Bean 的所有實(shí)例化啡氢、初始化都委托給外部函數(shù)時(shí)用的記錄位置状囱。

earlySingletonObjectssingletonFactories是一起用的,用來(lái)解決單例 bean 的循環(huán)依賴(lài)問(wèn)題倘是。一般在上面的"將 Bean 的所有實(shí)例化亭枷、初始化都委托給外部函數(shù)"中的外部函數(shù)中自行使用。

線(xiàn)程安全問(wèn)題

只有singletonObjects采用了線(xiàn)程安全的集合搀崭,此類(lèi)的復(fù)雜操作時(shí)都自行使用了隱式鎖叨粘。這點(diǎn)做的很全面×龆茫【在個(gè)別方法沒(méi)有用鎖的(例如isDependent)是因?yàn)橛?code>private升敲,在調(diào)用它的public中加了鎖『浯】

因?yàn)?code>singletonObjects要暴露出去驴党,所以采用線(xiàn)程安全的集合也是完全可以理解的。

單例 Bean 的循環(huán)依賴(lài)問(wèn)題

一般获茬,我們?cè)谶M(jìn)行單例 Bean 的生成和注冊(cè)時(shí)都是用的提供的擴(kuò)展方法鼻弧,傳入一個(gè)創(chuàng)建、初始化的方法來(lái)做锦茁。在這種情況下,一個(gè)單例 Bean 的流轉(zhuǎn)順序我們?cè)?code>DefaultSingletonRegistry的角度看大概是這樣的:

2.png

感覺(jué)自己時(shí)序圖畫(huà)的完全不符合規(guī)范叉存。

主要目的是說(shuō)明在各個(gè)緩存塊之間的流轉(zhuǎn)關(guān)系码俩,這個(gè)后面想個(gè)好點(diǎn)的、更直觀的表達(dá)方式吧歼捏。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末稿存,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子瞳秽,更是在濱河造成了極大的恐慌瓣履,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,589評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件练俐,死亡現(xiàn)場(chǎng)離奇詭異袖迎,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評(píng)論 3 396
  • 文/潘曉璐 我一進(jìn)店門(mén)燕锥,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)辜贵,“玉大人,你說(shuō)我怎么就攤上這事归形⊥锌” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,933評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵暇榴,是天一觀的道長(zhǎng)厚棵。 經(jīng)常有香客問(wèn)我,道長(zhǎng)蔼紧,這世上最難降的妖魔是什么婆硬? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,976評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮歉井,結(jié)果婚禮上柿祈,老公的妹妹穿的比我還像新娘。我一直安慰自己哩至,他們只是感情好躏嚎,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,999評(píng)論 6 393
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著菩貌,像睡著了一般卢佣。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上箭阶,一...
    開(kāi)封第一講書(shū)人閱讀 51,775評(píng)論 1 307
  • 那天虚茶,我揣著相機(jī)與錄音,去河邊找鬼仇参。 笑死嘹叫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的诈乒。 我是一名探鬼主播罩扇,決...
    沈念sama閱讀 40,474評(píng)論 3 420
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼怕磨!你這毒婦竟也來(lái)了喂饥?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,359評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤肠鲫,失蹤者是張志新(化名)和其女友劉穎员帮,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體导饲,經(jīng)...
    沈念sama閱讀 45,854評(píng)論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡捞高,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,007評(píng)論 3 338
  • 正文 我和宋清朗相戀三年氯材,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片棠枉。...
    茶點(diǎn)故事閱讀 40,146評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡浓体,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出辈讶,到底是詐尸還是另有隱情命浴,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評(píng)論 5 346
  • 正文 年R本政府宣布贱除,位于F島的核電站生闲,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏月幌。R本人自食惡果不足惜碍讯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,484評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望扯躺。 院中可真熱鬧捉兴,春花似錦、人聲如沸录语。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,029評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)澎埠。三九已至虽缕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蒲稳,已是汗流浹背氮趋。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,153評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留江耀,地道東北人剩胁。 一個(gè)月前我還...
    沈念sama閱讀 48,420評(píng)論 3 373
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像祥国,于是被迫代替她去往敵國(guó)和親摧冀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,107評(píng)論 2 356

推薦閱讀更多精彩內(nèi)容