SingletonBeanRegistry(单例 Bean 注册)接口


这个接口就是用来注册和获取单例 bean 的,ConfigurableBeanFactory 接口扩展了这个接口,这样做是为了暴露注册单例 bean 的功能,你可以通过 Spring 容器手动注册单例 Bean。

这个接口下面有以下方法:

  • registerSingleton
  • getSingleton
  • containsSingleton
  • getSingletonNames
  • getSingletonCount

DefaultSingletonBeanRegistry

这个类是 SingletonBeanRegistry 接口的默认实现,也支持注册 DisposableBean 实例,该类解决 Bean 依赖问题、Bean 循环引用问题、Bean 正在创建中问题。

注意:该类的中的方法是线程安全的,使用的是 synchronized。

public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {

registerSingleton

如果我们要手动向 Spring 容器中直接添加单例 bean 可以使用这个方法,这个方法是将 "singletonObject" 指定的对象做为单例 bean 注册到 "beanName" 下;但是,在 Spring 容器内部,并不是调用这个方法来完成单例 bean 注册。

void registerSingleton(String beanName, Object singletonObject);

执行流程:

  1. 直接从单例 bean 的缓存中通过 "beanName" 获取 bean 实例。注意:单例 bean 的缓存是 ConcurrentHashMap 类型,缓存名称叫 singletonObjects(也叫单例池),里面缓存了 bean 名称和单例 bean 实例的映射。
  2. 获取到了就会抛出 IllegalStateException(非法状态异常),说明 "beanName" 下面已经注册了单例 bean,没有办法再注册了。
  3. 没有获取到就会将 "beanName" 做为 key,"singletonObject" 做为 value 添加到单例 bean 的缓存中,同时移除 singletonFactories 和 earlySingletonObjects 缓存中的 "beanName",并将已经注册好的单例 bean 名称缓存(保存在 LinkedHashSet 中,单例 bean 名称按注册顺序排列)。

注意:

  1. "singletonObject" 实例必须是最终的,最终的意思并不是说这个类使用 final 关键字修饰,而是说你的这个对象所依赖的其它对象都已经实例化了并且关联了依赖,当 "singletonObject" 实例获取出来就能直接使用;也就是说 registerSingleton 方法不会帮你解决依赖问题。
  2. 不会执行 InitializingBean#afterPropertiesSet 方法(初始化回调)和 DisposableBean#destroy 方法(销毁回调)。如果你想执行这两个回调方法,应该注册 BeanDefinition。

getSingleton

通过指定的 "beanName" 返回单例 bean 对象,这个方法只会获取到已经实例化的单例 bean。

public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
}

执行流程:

注意:

  1. 这个方法可以获取到 registerSingleton 注册的单例 bean 和 BeanDefinition 的单例 bean。
  2. 这个方法不支持 FactoryBean 的前缀或 bean 的别名。

值得注意的是:这一块挺不好理解的,可以先看下面的 扩展知识点—Spring Bean 缓存。


SingletonBeanRegistry 接口的其它方法

这个接口剩下了 containsSingleton、getSingletonNames、getSingletonCount 这三个方法;没有必要去看这三个方法的具体实现,需要记住的是:

  1. 它们使用的都是单例 bean 的缓存(singletonObjects),也就是说这三个方法只会判断被实例化的单例 bean。
  2. 单例 bean 的缓存(singletonObjects)中保存了 registerSingleton 注册的单例 bean 和 BeanDefinition 已经实例化了的单例 bean。

getSingleton(String, ObjectFactory<?>)

这个方法是 DefaultSingletonBeanRegistry 类新增的方法。该方法也是通过 "beanName" 获取单例 bean,但是当获取不到单例 bean 时,会通过 "singletonFactory" 创建单例 bean 并返回。

public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {

执行流程:

首先这个方法要注意的地方和 getSingleton 方法要注意的地方是一样的,只不过又增加了前置检查和后置检查需要注意的地方:

  1. 前置检查:先判断 "beanName" 需不需要检查,需要检查就会判断 "beanName" 是不是正在创建;这样做就是为了防止并发时重复创建。
    protected void beforeSingletonCreation(String beanName) {
        if (!this.inCreationCheckExclusions.contains(beanName) &&
                !this.singletonsCurrentlyInCreation.add(beanName)) {
            throw new BeanCurrentlyInCreationException(beanName);
        }
    }
    
  2. 后置检查:先判断 "beanName" 需不需要检查,需要检查就会判断 "beanName" 是不是正在创建;这样做就是为了防止并发时重复创建。
    
    

扩展知识点—Spring Bean 缓存

asdasdasd


扩展知识点—ObjectFactory 接口

这个接口通常用于封装通用工厂,每次调用 getObject 方法的时候都会返回目标对象,这个对象可以是单例也可以是非单例的。

值得注意的是:这个接口虽然和 FactoryBean 类似,但后者的实现通常意味着定义为 BeanFactory 中的 SPI 实例,而此类的实现通常意味着作为 API 提供给其他 bean(通过注入)。 因此,getObject() 方法具有不同的异常处理行为。

这个接口在 Spring 中的默认实现:

  • RequestObjectFactory
  • ResponseObjectFactory
  • SessionObjectFactory
  • WebRequestObjectFactory
  • TargetBeanObjectFactory