Spring IOC(三)单例 bean 的注册管理

Spring IOC(三)单例 bean 的注册管理

Spring 系列目录(https://www.cnblogs.com/binarylei/p/10198698.html)

Spring IOC(三)单例 bean 的注册管理_第1张图片

在 Spring 中 Bean 有单例和多例之分,只有单例的 bean 才会被 BeanFactory 管理,这个工作就是由 SingletonBeanRegistry 完成的。

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,主要功能如下:

  1. 单例 bean 的注册和查找。
  2. 扩展了 SingletonBeanRegistry 的功能,还管理 bean 的生命周期,包括 bean 的创建和销毁。与 bean 生命周期有关的方法如下:
// 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。

// 1.1 保存最终创建成功的单例 beanName -> beanInstance
private final Map singletonObjects = new ConcurrentHashMap<>(256);
// 1.2 中间变量,beanName -> Objectfactory
private final Map> singletonFactories = new HashMap<>(16);
// 1.3 中间变量,bean 还在创建的时候就可以获取,用于检测循环引用 
private final Map earlySingletonObjects = new HashMap<>(16);

// 2. 用来保存当前所有已注册的 bean
private final Set registeredSingletons = new LinkedHashSet<>(256);

这里涉及用于存储 bean 的不同的 Map,可能让人感到崩溃,简单解释如下:

  1. singletonObjects:用于保存 beanName 和创建 bean 实例之间的关系,beanName -> beanInstance
  2. singletonfactories:用于保存 beanname 和创建 bean 的工厂之间的关系,beanName -> Objectfactory
  3. earlySingletonObjects:也是保存 beanName 和创建 bean 实例之间的关系,与 singletonObjects 的不同之处在于,当一个单例 bean 被放到这里面后,那么当 bean 还在创建过程中,就可以通过 getBean 方法获取到了,其目的是用来检测循环引用。
  4. registeredsingletons:用来保存当前所有已注册的 bean

(2) 与单例对象创建有关的几个属性

// 1. 保存正在创建的 bean
private final Set singletonsCurrentlyInCreation =
            Collections.newSetFromMap(new ConcurrentHashMap<>(16));
// 2. 保存已经创建的 bean 集合,这样进行依赖循环检查时
//    如果已经 bean 在 inCreationCheckExclusions 中了,就不用再检查 singletonsCurrentlyInCreation 了
private final Set inCreationCheckExclusions =
        Collections.newSetFromMap(new ConcurrentHashMap<>(16));
// 3. 保存 bean 创建过程时的异常
private Set suppressedExceptions;

(3) 与单例对象销毁有关的四个集合

// 1. 一旦调用 destroySingletons() 销毁所有的 bean 时就修改为 true 
private boolean singletonsCurrentlyInDestruction = false;

// 2. 下面四个集合都和 bean 的销毁有关
// 2.1 保存每个 bean 的 destroy 方法
private final Map disposableBeans = new LinkedHashMap<>();

// 3.1 保存当前 bean 内的所有 bean 信息。containingBean -> containedBean
//      当注册 containedBeanMap 的同时也会注册 dependentBeanMap 和 dependenciesForBeanMap
private final Map> containedBeanMap = new ConcurrentHashMap<>(16);

// 3.2 保存依赖这个 bean 的所有 bean 的集合,依赖我的。containedBean -> containingBean
//     所以销毁这个 bean 的同时也要销毁依赖它的所有 bean
private final Map> dependentBeanMap = new ConcurrentHashMap<>(64);
// 3.3 保存当前 bean 依赖的所有 bean 的集合,我依赖的。containingBean -> containedBean
//     所以销毁这个 bean 只要清空对应的记录即可,而不会销毁该 bean 依赖的其它 bean
private final Map> dependenciesForBeanMap = new ConcurrentHashMap<>(64);

二、bean 的注册与删除

@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 中:

  • 一是 bean 创建完成直接注册 singletonObjects。此时 bean 已经创建完成,直接注册到 singletonObjects 集合中,同时清理创建过程中所记录的各种辅助状态。
  • 二是 bean 创建开始前先注册其引用对象 singletonFactory。此时先注册到 singletonFactories 中,通过 allowEarlyReference=true 可以查找到提前暴露的这个对象,一旦创建完成调用 addSingleton(String beanName, Object singletonObject) 将其注册到 singletonObjects 中,这段代码的逻辑见 getSingleton(String beanName, ObjectFactory singletonFactory) 方法。

三、bean 的生周期

DefaultSingletonBeanRegistry 不仅管理了 bean 的注册,还管理 bean 的生命周期,包括 bean 的创建和销毁。

3.1 bean 的创建

Spring 中单例只会被创建一次,后续再获取 bean 直接从单例缓存中获取。

  1. 尝试从缓存中查找。getSingleton(beanName) 直接从缓存中获取 bean,也可以指定是否查找提前暴露的 bean(也就是正在创建的 bean)。allowEarlyReference=true 时会查找正在创建的 bean。
  2. 直接创建 bean。当从缓存中获取不到时,直接会调用 getSingleton(beanName, singletonFactory) 方法创建单例 bean。因为创建的时候会存在依赖注入的情况,为了解决可能存在的循环依赖问题,Spring 创建 bean 的原则是不等 bean 创建完成就会将创建 bean 的 ObjectFactory 提早曝光加入到缓存中,这样通过 getSingleton(beanName, true) 就可以在缓存中直接查找到这个 bean 的 ObjectFactory。

3.1.1 从缓存中获取

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);
}

这个方法步骤如下:

  1. 首先尝试从 singletonObjects 里面获取实例
  2. 如果获取不到再从 earlySingletonObjects 里面获取
  3. 如果还获取不到,再尝试从 singletonFactories 里面获取 beanName 对应的 ObjectFactory,然后调用这个 ObjectFactory 的 getObject 来创建 bean,并放到 earlySingletonObjects 里面去,并且从 earlySingletonObjects 里面 remove 掉这个 ObjectFactory

而对于后续的所有内存操作都只为了循环依赖检测时候使用,也就是在 allowEarlyReference=true 的情况下才会使用。

3.1.2 直接创建 bean

上面讲解了从缓存中获取单例的过程,那么,如果缓存中不存在已经加载的单例 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();
            }
            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 过程中所记录的各种辅助状态。

3.1.3 ObjectFactory 参数

在创建 bean 的过程中,很多工作都交给 ObjectFactory 这个工厂类完成,那它到底是什么呢?

public interface ObjectFactory {
    T getObject() throws BeansException;
}

在方法 getSingleton(beanName, singletonFactory)addSingletonFactory(beanName, singletonFactory) 两种都用到了 ObjectFactory,这两处的 ObjectFactory 功能并不是一样的。 前者的 ObjectFactory 是用于创建 bean,属于创建型 ObjectFactory,而后者只是简单的持有 bean,属于引用型 ObjectFactory,保存在 singletonFactories 集合中用于解决循环依赖的问题。

(1) 创建型 ObjectFactory

protected  T doGetBean(final String name, @Nullable final Class requiredType,
            @Nullable final Object[] args, boolean typeCheckOnly) throws BeansException {
    sharedInstance = getSingleton(beanName, new ObjectFactory() {
        @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);
}

3.1.4 bean 的状态管理

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);
}

3.2 bean 的依赖管理

bean 创建成功后需要注册 bean 之前的依赖关系,这样销毁时才能将依赖它的 bean 也同时销毁

3.2.1 依赖管理

(1) 注册依赖

// 保存当前 bean 内的所有 bean。containingBeanName -> containedBeanName
public void registerContainedBean(String containedBeanName, String containingBeanName) {
    synchronized (this.containedBeanMap) {
        Set 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 dependentBeans =
                this.dependentBeanMap.computeIfAbsent(canonicalName, k -> new LinkedHashSet<>(8));
        // 如果已经注册直接返回
        if (!dependentBeans.add(dependentBeanName)) {
            return;
        }
    }
    synchronized (this.dependenciesForBeanMap) {
        Set 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 的所有 bean
  • getDependenciesForBean 查找这个 bean 依赖的所有 bean

isDependent 查找两个 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 alreadySeen) {
    // 1. alreadySeen 是已经查找过的 bean,这里面的 bean 都不存在依赖关系,如果存在则已经返回 true 了
    if (alreadySeen != null && alreadySeen.contains(beanName)) {
        return false;
    }
    // 2. 获取 bean 的注册名称
    String canonicalName = canonicalName(beanName);
    // 3. 查找依赖 beanName 的所有 bean,如果有则肯定有依赖,否则还要查找间接依赖
    Set 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;
}

3.3 bean 的销毁

// 销毁所有 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 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 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>> it = this.dependentBeanMap.entrySet().iterator(); it.hasNext();) {
            Map.Entry> entry = it.next();
            Set dependenciesToClean = entry.getValue();
            dependenciesToClean.remove(beanName);
            if (dependenciesToClean.isEmpty()) {
                it.remove();
            }
        }
    }

    // 5. 清理 dependenciesForBeanMap
    this.dependenciesForBeanMap.remove(beanName);
}

每天用心记录一点点。内容也许不重要,但习惯很重要!

你可能感兴趣的:(Spring IOC(三)单例 bean 的注册管理)