【小家Spring】Spring的单例Bean定注册中心SingletonBeanRegistry详解

简介: 【小家Spring】Spring的单例Bean定注册中心SingletonBeanRegistry详解

前言


上一篇重点介绍了bean定义信息的注册:

【小家Spring】Spring的Bean定义注册中心BeanDefinitionRegistry详解


本文着眼于Spring的Bean中最重要的类型:单例Bean。研究它的注册中心:SingletonBeanRegistry


SingletonBeanRegistry


此接口是针对Spring中的单例Bean设计的。提供了统一访问单例Bean的功能。比如我们熟悉的接口ConfigurableBeanFactory就继承了此接口


ConfigurableListableBeanFactory是它的子接口,DefaultListableBeanFactory是它的实现类。

AbstractBeanFactory、AbstractAutowireCapableBeanFactory也是ConfigurableListableBeanFactory的子接口

基本上可以说除了HierarchicalBeanFactory没有继承此接口,其余的都有直接或间接的实现~~~~



image.png


我们能够发现,最终真正实现这个接口的,都是BeanFactory


// @since 2.0 Spring2之后才出来这个接口
public interface SingletonBeanRegistry {
  //  以指定的名字  把Object放进去
  // 1、给定的Object必须是被完全初始化了的(比如new出来的)
  // 2、此注册接口不会提供任何用以初始化的回调函数(比如:InitializingBean、afterPropertiesSet都是不会执行的)
  // 3、如果此接口的实现类是一个BeanFactory,最好最好最好将你的类注册成Bean Definition而不是直接使用对象(这样就可以使你定义的Bean收到initialization和destruction回调)
  void registerSingleton(String beanName, Object singletonObject);
  // 仅仅返回已经初始化完成的Bean,对于还没有初始化的Bean Definition不予以考虑
  // 但是要注意,此方法**并不支持使用别名**对Bean进行查找,如果只有别名的话,要先通过BeanFactory的接口获取到Bean对应的全限定名称(transformedBeanName())
  @Nullable
  Object getSingleton(String beanName);
  // 检查此实例是否包含指定名字的并且!!!已经初始化完成的单例Bean(不支持别名查找)
  // BeanFactory#containsBean是containsSingleton(beanName) || containsBeanDefinition(beanName)
  boolean containsSingleton(String beanName);
  // 返回容器内所有单例类的名字
  String[] getSingletonNames();
  // 返回容器内注册的单例类数量
  int getSingletonCount();
  //@since 4.2 mutex:互斥量  互斥体
  Object getSingletonMutex();
}


同样的,按照它的继承结构,着重分析几个典型实现。


DefaultSingletonBeanRegistry


注意:这个和DefaultSingletonBeanRegistry不一样,这个类非常非常的重要,并且做的事情也很多。甚至认为是Spring容器 所谓的容器的核心内容。 他里面有非常多的缓存,需要解决Bean依赖问题、Bean循环引用问题、Bean正在创建中问题。。。


它继承SimpleAliasRegistry类和实现了SingletonBeanRegistry接口,因此这个类可以有别名注册的功能和单例bean注册的功能,并且他还支持注册DisposableBean实例;它依赖ObjectFactory接口和DisposableBean接口(关闭注册表时调用到了destroy方法)。

//共享bean实例的通用注册表 实现了SingletonBeanRegistry. 允许注册表中注册的单例应该被所有调用者共享,通过bean名称获得。 
// 可以注册bean之间的依赖关系,执行适当的注入、关闭顺序
// 这个类主要用作基类的BeanFactory实现, 提供基本的管理 singleton bean 实例功能
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
  // ==========它里面维护了非常非常多的Map、List等  这些构成了我们所谓的容器==========
  // 很显然:所有的单例bean最终都会到这里来
  private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
  //缓存了bean的name 和  ObjectFactory。  因为最终的Bean都是通过ObjectFactory的回调方法来创建的
  private final Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>(16);
  // 缓存了已经存在单例,用于解决循环依赖的方法 循环依赖
  // 是存放singletonFactory 制造出来的 singleton 的缓存早期单例对象缓存
  private final Map<String, Object> earlySingletonObjects = new HashMap<>(16);
  // 已经注册好的单例bean的名称们  和 singletonObjects保持同步
    private final Set<String> registeredSingletons = new LinkedHashSet<String>(256);
  // ===================以上四个缓存是这个类存放单例bean的主要Map  ===========================
  // 目前正在创建中的单例bean的名称的集合   存着正在初始化的Bean级不要再次发起初始化了 ===注意是正在===
  private final Set<String> singletonsCurrentlyInCreation = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
  // 直接缓存当前不能加载的bean
  // 这个值是留给开发者自己set的,Spring自己不会往里面放值~~~~
  private final Set<String> inCreationCheckExclusions = Collections.newSetFromMap(new ConcurrentHashMap<>(16));
  //存放异常出现的相关的原因的集合
    private Set<Exception> suppressedExceptions;  
  //标志,指示我们目前是否在销毁单例中</span><span>  
    private boolean singletonsCurrentlyInDestruction = false;  
  // 一次性Bean  也就是说Bean是DisposableBean接口的实现
  // 实现DisposableBean接口的类,在类销毁时,会调用destroy()方法,开发人员可以重新该方法完成自己的工作
  // 目前像里添加的只有`AbstractBeanFactory#registerDisposableBeanIfNecessary`  其实还是来自于  doCreateBean方法
  private final Map<String, Object> disposableBeans = new LinkedHashMap<>();
  private final Map<String, Set<String>> containedBeanMap = new ConcurrentHashMap<>(16);
  // 查找依赖的类   我依赖了哪些们
  private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
  //被依赖的bean key为beanName    我被哪些们依赖了
  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);
      // 注意:此处是如果此单例bean已经存在了,直接抛出异常~~~~~
      if (oldObject != null) {
        throw new IllegalStateException("Could not register object [" + singletonObject +
            "] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
      }
      addSingleton(beanName, singletonObject);
    }
  }
  // 添加进去一个实例,实际上它做了好几步操作呢
  // singletonObjects和singletonFactories是对立关系  不会同时存在
  protected void addSingleton(String beanName, Object singletonObject) {
    // 注意此处继续上锁
    synchronized (this.singletonObjects) {
      // 添加进map缓存起来
      this.singletonObjects.put(beanName, singletonObject);
      // 因为已经添加进去了,所以Factories就可议移除了~~~
      this.singletonFactories.remove(beanName);
      //已经存在单例(循环依赖)也可以移除了~~~
      this.earlySingletonObjects.remove(beanName);
      // beanName放进单例注册表中  
      this.registeredSingletons.add(beanName);
    }
  }
  // 注意:它是一个protected方法,并不是接口方法。子类会向这里添加工厂的~~~
  protected void addSingletonFactory(String beanName, ObjectFactory<?> singletonFactory) {
    synchronized (this.singletonObjects) {
      // 首先判断一下:这个bean没有被产生才需要添加工厂,否则啥都不做~~~
      //  判断singletonObjects内名字为beanName是否被占用,若没有,进行注册操作  
      if (!this.singletonObjects.containsKey(beanName)) {
        this.singletonFactories.put(beanName, singletonFactory);
        //已经存在单例(循环依赖)也可以移除了~~~ 
        this.earlySingletonObjects.remove(beanName);
        // 注意注意注意:此处beanName也缓存了哦~~~一定要注意
        this.registeredSingletons.add(beanName);
      }
    }
  }
  // SingletonBeanRegistry接口的getSingleton方法的实现 
  @Override
  @Nullable
  public Object getSingleton(String beanName) {
    return getSingleton(beanName, true);
  }
  // allowEarlyReference:是否要创建早期引用
  @Nullable
  protected Object getSingleton(String beanName, boolean allowEarlyReference) {
    // 先根据这个beanName去查找,找到value值
    Object singletonObject = this.singletonObjects.get(beanName);
    // 此处:如果此单例不存在,也不要立马就返回null了  还有工作需要处理呢
    // 这里的条件是:如果单例不存在,并且并且这个bean正在chuangjianzhong~~~(在这个singletonsCurrentlyInCreation集合了,表示它正在创建中) 
    // 什么时候放进这个集合表示创建中呢?调用beforeSingletonCreation()方法,因为他是protected方法,所以只允许本类和子类调用~
    if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
      synchronized (this.singletonObjects) {
        // 这里再去earlySingletonObjects去看一下,看是否有呢   如果有直接返回即可
        singletonObject = this.earlySingletonObjects.get(beanName);
        // 如果还未null,并且 并且allowEarlyReference是允许的  也就是说是允许创建一个早期引用的(简单的说就是先可以把引用提供出去,但是并还没有完成真正的初始化~~~~)
        // 这里ObjectFactory就发挥很大的作用了~~~
        if (singletonObject == null && allowEarlyReference) {
          ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
          // 若有对应的ObjectFactory 那就可以继续处理
          // 备注:singletonFactories这个Map只有调用`addSingletonFactory()`方法的时候才往里添加
          // 它是一个protected方法,目前Spring还只有在`AbstractAutowireCapableBeanFactory#doCreateBean`里有过调用
          if (singletonFactory != null) {
            singletonObject = singletonFactory.getObject();
            // 注意此处:把生产出来的放进earlySingletonObjects里面去,表示生产出来了一个引用
            this.earlySingletonObjects.put(beanName, singletonObject);
            // 然后把nFactories可以移除了,因为引用已经产生了~~~
            this.singletonFactories.remove(beanName);
          }
        }
      }
    }
    return singletonObject;
  }
  // 这个方法蛮重要的。首先它不是接口方法,而是一个单纯的public方法~~~
  // 它的调用处只有一个地方:AbstractBeanFactory#doGetBean  在真正 `if (mbd.isSingleton()) { sharedInstance = getSingleton(...) }`
  // 它第二个参数传的是ObjectFactory~~~~~~~实现有创建Bean实例的逻辑~~~
  public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
    // 在锁内工作~~~~
    synchronized (this.singletonObjects) {
      Object singletonObject = this.singletonObjects.get(beanName);
      // 很显然如果都不为null了,那还做什么呢  直接返回吧
      if (singletonObject == null) {
        // 如果目前在销毁singellton 那就抛异常呗~~~~
        if (this.singletonsCurrentlyInDestruction) {
          //  抛异常
        }
        // 标记这个bean正在被创建~~~~
        beforeSingletonCreation(beanName);
        boolean newSingleton = false;
        try {
          singletonObject = singletonFactory.getObject();
          newSingleton = true;
        } catch (IllegalStateException ex) {
          ... // 省略 
        } finally {
          // 释放这个状态  说明这个bean已经创建完成了
          afterSingletonCreation(beanName);
        }
        // 如果是新创建了  这里执行一下添加  缓存起来~~~~
        // 如果是旧的  是不用添加的~~~~
        if (newSingleton) {
          addSingleton(beanName, singletonObject);
        }
      }
      return singletonObject;
    }
  }
  // 这两个方法 一个在Bean创建开始之前还行。一个在创建完成后执行 finally里执行
  // 表示;beforeSingletonCreation()方法用于记录加载的状态  表示该Bean当前正在初始化中~~~
  // 调用this.singletonsCurrentlyInCreation.add(beanName)将当前正要创建的bean记录在缓存中,这样便可以对循环依赖进行检测啦
  // afterSingletonCreation显然就是
  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");
    }
  }
  // 直接检查 singleton object 存储器了,其他的存储器不做检查
  @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();
    }
  }
  // 这个方法  只是简单的把这个Map返回出去了~~~~~
  @Override
  public final Object getSingletonMutex() {
    return this.singletonObjects;
  }
}


getSingleton的时候,spring的默认实现是,先从 singleton object 的存储器中去寻找,如果找不到,再从 early singleton object 存储器中寻找,再找不到,那就在寻找对应的 singleton factory,造出所需的 singleton object,然后返回


管理bean的依赖问题, 使用如下三个属性进行管理:

Map<String, Set<String>> containedBeanMap // 依赖的bean name为key , 就是依赖类 -> 查找 被依赖的类
Map<String, Set<String>> dependentBeanMap // 依赖的原始bean name为key
Map<String, Set<String>> dependenciesForBeanMap // 被依赖的bean name为key


这就是DefaultSingletonBeanRegistry,它实现了接口的所有方法。它还有实现很多Bean依赖之间关系的逻辑,此处不展开了~~~


DefaultSingletonBeanRegistry既有管理SingletonBean 的功能,又提供了别名的功能。DefaultSingletonBeanRegistry是一个通用的存储共享bean实例的地方,通过bean的名字获得bean。同时,它也给提供一次性bean的注册功能

image.png


FactoryBeanRegistrySupport


FactoryBeanRegistrySupport是 工厂bean(FactoryBean)注册的一个超类,它是一个抽象类,内部多了一个成员变量:


private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);


它负责缓存由工厂bean产生的单例bean。它还额外增加了一些方法,用于通过 工厂bean获取 工厂bean所创建的对象的一些信息,下面看看源码:


// 可议看到它是一个首相类,并且继承自`DefaultSingletonBeanRegistry `
public abstract class FactoryBeanRegistrySupport extends DefaultSingletonBeanRegistry {
  private final Map<String, Object> factoryBeanObjectCache = new ConcurrentHashMap<>(16);
  // 获取factoryBean的类型。  它相对于factoryBean.getObjectType()主要是增加了一些安全校验   这里相关源码我都省略了
  @Nullable
  protected Class<?> getTypeForFactoryBean(final FactoryBean<?> factoryBean) {
    return factoryBean.getObjectType();
  }
  // 直接从缓存中拿  工厂Bean制造出来的对象
  @Nullable
  protected Object getCachedObjectForFactoryBean(String beanName) {
    return this.factoryBeanObjectCache.get(beanName);
  }
  // 核心方法:从工厂Bean里面拿到这个对象~
  protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
    // 是单例,并且已经存在该beanName了
    if (factory.isSingleton() && containsSingleton(beanName)) {
      // 仍然采用这把锁  互斥锁
      synchronized (getSingletonMutex()) {
        Object object = this.factoryBeanObjectCache.get(beanName);
        // 显然只有factoryBeanObjectCache里不存在此bean,才需要继续去工厂Bean里面找~
        if (object == null) {
          // 其实就基本相当于 factory.getObject()
          object = doGetObjectFromFactoryBean(factory, beanName);
          ...
          this.factoryBeanObjectCache.put(beanName, object);
        }
        return object;
      }
    }
    ...
  }
  /**
   * Post-process the given object that has been obtained from the FactoryBean.
   * The resulting object will get exposed for bean references.
   * <p>The default implementation simply returns the given object as-is.
   * Subclasses may override this, for example, to apply post-processors.
   * @param object the object obtained from the FactoryBean.
   * @param beanName the name of the bean
   * @return the object to expose
   * @throws org.springframework.beans.BeansException if any post-processing failed
   */
  protected Object postProcessObjectFromFactoryBean(Object object, String beanName) throws BeansException {
    return object;
  }
  /**
   * Overridden to clear the FactoryBean object cache as well.
   */
  @Override
  protected void removeSingleton(String beanName) {
    synchronized (getSingletonMutex()) {
      super.removeSingleton(beanName);
      this.factoryBeanObjectCache.remove(beanName);
    }
  }
  // 这里复写了父类的方法。注意:调用了super的方法
  @Override
  protected void clearSingletonCache() {
    synchronized (getSingletonMutex()) {
      super.clearSingletonCache();
      this.factoryBeanObjectCache.clear();
    }
  }
  // 获取安全上下文
  protected AccessControlContext getAccessControlContext() {
    return AccessController.getContext();
  }
}


它有个唯一子类:AbstractBeanFactory,它可议说是整个BeanFactory实现的大脑。因为AbstractBeanFactory继承自FactoryBeanRegistrySupport,所以不仅仅有注册单例Bean的能力,也有注册工厂Bean的能力了。


到后面的抽象子类AbstractAutowireCapableBeanFactory,再到实现类DefaultListableBeanFactory就都有这个功能了。


这里面还有一个继承分支:ConfigurableBeanFactory有直接继承此接口。同时AbstractBeanFactory和ConfigurableListableBeanFactory也都继续继承了ConfigurableBeanFactory。


而对于ConfigurableListableBeanFactory它只有唯一实现类:DefaultListableBeanFactory


手动注册单例Bean的方式


基本上我们只要能拿到Bean工厂(一般都可以通过注入的方式拿到),就可以调用SingletonBeanRegistry的相关方法对容器内的单例Bean做一些列的操作~~~


总结


仔细想想,为什么这个类DefaultSingletonBeanRegistry要使用三个存储器呢:


singletonObjects:就是直观的存储着 singleton 的

singletonFactories:是存储的制造 singleton 的工厂

earlySingletonObject:这是一个 早期 singletonFactory 制造出来的 singleton 的缓存

这样处理的好处,是解决依赖、循环依赖的问题。

相关文章
|
24天前
|
缓存 Java Spring
Spring 框架中 Bean 的生命周期
Spring 框架中 Bean 的生命周期
32 1
|
1月前
|
XML Java 开发者
Spring Boot中的bean注入方式和原理
Spring Boot中的bean注入方式和原理
59 0
|
1月前
|
XML 缓存 Java
Spring源码之 Bean 的循环依赖
循环依赖是 Spring 中经典问题之一,那么到底什么是循环依赖?简单说就是对象之间相互引用, 如下图所示: 代码层面上很好理解,在 bean 创建过程中 class A 和 class B 又经历了怎样的过程呢? 可以看出形成了一个闭环,如果想解决这个问题,那么在属性填充时要保证不二次创建 A对象 的步骤,也就是必须保证从容器中能够直接获取到 B。 一、复现循环依赖问题 Spring 中默认允许循环依赖的存在,但在 Spring Boot 2.6.x 版本开始默认禁用了循环依赖 1. 基于xml复现循环依赖 定义实体 Bean java复制代码public class A {
|
1月前
|
存储 NoSQL Java
Spring Boot统计一个Bean中方法的调用次数
Spring Boot统计一个Bean中方法的调用次数
35 1
|
2月前
|
Java 索引 Spring
spring创建bean的过程
spring创建bean的过程
|
9天前
|
Java 数据库连接 开发者
浅谈Spring的Bean生命周期
浅谈Spring的Bean生命周期
17 1
|
13天前
|
XML Java 数据格式
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
19 0
Bean工厂探秘:解析Spring底层工厂体系BeanFactory的神奇之道
|
23天前
|
XML Java 程序员
作为Java程序员还不知道Spring中Bean创建过程和作用?
作为Java程序员还不知道Spring中Bean创建过程和作用?
14 0
|
28天前
|
XML 缓存 Java
天天用 Spring,bean 实例化原理你懂吗
天天用 Spring,bean 实例化原理你懂吗
17 0
|
1月前
|
Java Spring
Spring5深入浅出篇:bean的生命周期
Spring5深入浅出篇:bean的生命周期