返回介绍

5.4 获取单例

发布于 2025-04-22 22:09:10 字数 4320 浏览 0 评论 0 收藏

之前我们讲解了从缓存中获取单例的过程,那么,如果缓存中不存在已经加载的单例 bean 就需要从头开始 bean 的加载过程了,而 Spring 中使用 getSingleton 的重载方法实现 bean 的加载过程。

public Object getSingleton(String beanName, ObjectFactory singletonFactory) {

  Assert.notNull(beanName, "'beanName' must not be null");

 //全局变量需要同步

  synchronized (this.singletonObjects) {

  //首先检查对应的 bean 是否已经加载过,因为 singleton 模式其实就是复用以创建的 bean,所

  以这一步是必须的

   Object singletonObject = this.singletonObjects.get(beanName);

  //如果为空才可以进行 singleto 的 bean 的初始化

   if (singletonObject == null) {

    if (this.singletonsCurrentlyInDestruction) {

     throw new BeanCreationNotAllowedException(beanName,

     "Singleton bean creation not allowed while the 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 + "'");

   }

   beforeSingletonCreation(beanName);

    boolean recordSuppressedExceptions = (this.suppressedExceptions == null);

    if (recordSuppressedExceptions) {

     this.suppressedExceptions = new LinkedHashSet<Exception>();

   }

    try {

    //初始化 bean

     singletonObject = singletonFactory.getObject();

   }

    catch (BeanCreationException ex) {

     if (recordSuppressedExceptions) {

      for (Exception suppressedException : this.suppressedExceptions) {

      ex.addRelatedCause(suppressedException);

     }

    }

     throw ex;

   }

    finally {

     if (recordSuppressedExceptions) {

      this.suppressedExceptions = null;

    }

    afterSingletonCreation(beanName);

   }

   //加入缓存

   addSingleton(beanName, singletonObject);

  }

   return (singletonObject != NULL_OBJECT ? singletonObject : null);

 }

}

上述代码中其实是使用了回调方法,使得程序可以在单例创建的前后做一些准备及处理操作,而真正的获取单例 bean 的方法其实并不是在此方法中实现的,其实现逻辑是在 ObjectFactory 类型的实例 singletonFactory 中实现的。而这些准备及处理操作包括如下内容。

(1)检查缓存是否已经加载过。

(2)若没有加载,则记录 beanName 的正在加载状态。

(3)加载单例前记录加载状态。

可能你会觉得 beforeSingletonCreation 方法是个空实现,里面没有任何逻辑,但其实不是,这个函数中做了一个很重要的操作:记录加载状态,也就是通过 this.singletonsCurrentlyIn Creation.add(beanName) 将当前正要创建的 bean 记录在缓存中,这样便可以对循环依赖进行检测。

protected void beforeSingletonCreation(String beanName) {

  if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletons

  CurrentlyInCreation.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.singletons

  CurrentlyInCreation.remove(beanName)) {

   throw new IllegalStateException("Singleton '" + beanName + "' isn't currently

   in creation");

 }

}

(6)将结果记录至缓存并删除加载 bean 过程中所记录的各种辅助状态。

protected void addSingleton(String beanName, Object singletonObject) {

  synchronized (this.singletonObjects) {

   this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject :

  NULL_OBJECT));

  this.singletonFactories.remove(beanName);

  this.earlySingletonObjects.remove(beanName);

  this.registeredSingletons.add(beanName);

 }

}

(7)返回处理结果。

虽然我们已经从外部了解了加载 bean 的逻辑架构,但现在我们还并没有开始对 bean 加载功能的探索,之前提到过, bean 的加载逻辑其实是在传入的 ObjectFactory 类型的参数 singletonFactory 中定义的,我们反推参数的获取,得到如下代码:

sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {

  public Object getObject() throws BeansException {

   try {

    return createBean(beanName, mbd, args);

  }

   catch (BeansException ex) {

   destroySingleton(beanName);

    throw ex;

  }

 }

});

ObjectFactory 的核心部分其实只是调用了 createBean 的方法,所以我们还需要到 createBean 方法中追寻真理。

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。