从源码层面解读spring中bean的循环依赖解决方案(3)

写在前面的话

其实这一篇文章已经脱离了依赖循环的范畴了,上一篇文章已经解释循环依赖的解决方案了,但是还没有讲解完善,

这一篇就让我们再深入理一下吧。

在之前先一些问题进行详细的探讨。

主要探讨以下几个问题,如何将bean初始化,在什么时候初始化,如果缓存中没有bean时会怎么办?

第一个问题如何将bean初始化。

初始化bean

在bean的配置时bean中一个init-method的属性。这个属性的作用就是在bean实例化之前调用init-method指定的方法来根据用户业务进行相应的实例化。

这个方法的执行位置是在Spring程序已经执行过bean的实例化,并且进行了属性的填充,这是就会调用用户设定的初始化方法。

这也解释了在什么时候进行初始化

源码如下:

/**
 * Initialize the given bean instance, applying factory callbacks
 * as well as init methods and bean post processors.
 * 初始化给定的bean实例,应用工厂回调  
 * 以及初始化方法和bean后处理程序。 
 * <p>Called from {@link #createBean} for traditionally defined beans,
 * and from {@link #initializeBean} for existing bean instances.
 * @param beanName the bean name in the factory (for debugging purposes)
 * @param bean the new bean instance we may need to initialize
 * @param mbd the bean definition that the bean was created with
 * (can also be {@code null}, if given an existing bean instance)
 * @return the initialized bean instance (potentially wrapped)
 * @see BeanNameAware
 * @see BeanClassLoaderAware
 * @see BeanFactoryAware
 * @see #applyBeanPostProcessorsBeforeInitialization
 * @see #invokeInitMethods
 * @see #applyBeanPostProcessorsAfterInitialization
 */
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
   if (System.getSecurityManager() != null) {
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
         invokeAwareMethods(beanName, bean);
         return null;
      }, getAccessControlContext());
   }
   else {
      // 对特殊的bean处理:Aware、BeanClassLoaderAware、BeanFactoryAware
      invokeAwareMethods(beanName, bean);
   }

   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      // 应用前处理器
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   try {
      // 激活自定义的init方法
      invokeInitMethods(beanName, wrappedBean, mbd);
   }
   catch (Throwable ex) {
      throw new BeanCreationException(
            (mbd != null ? mbd.getResourceDescription() : null),
            beanName, "Invocation of init method failed", ex);
   }
   if (mbd == null || !mbd.isSynthetic()) {
      // 后处理器应用
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
   }

   return wrappedBean;
}

这个函数的主要目的是进行客户设定的初始化方法调用

但是除此之外还进行了一些其他的必要工作,这里也一并进行说明了。

1.激活Aware方法

在此之前介绍一下Aware的使用

Aware使用

Spring中提供了一些Aware相关接口,比如BeanFactoryAware、ResourceLoaderAware、ApplicationContextAware等,

实现这些接口的bean在被初始化之后,可以取得一些相应的资源,

例如实现BeanFactoryAware的bean在初始化后,Spring容器将会注入BeanFactory的实例,

而实现ApplicationContextAware的bean,在bean被初始后,将会被注入ApplicationContext的实例等。

举例说明:

1.定义普通的bean

@Component
public class Hello {
    public void say(){
        System.out.println("hello");
    }
}

2.定义BeanFactoryAware类型的bean

@Component
public class Test implements BeanFactoryAware {

    private BeanFactory beanFactory;

    @Override
    // 声明bean的时候Spring会自动注入BeanFactory
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    public void testAware(){
        // 通过hello这个bean id 从beanFactory获取实例
        Hello hello = (Hello) beanFactory.getBean("hello");
        hello.say();
    }
}
  1. 测试Springboot 的项目环境中测试方式如下:

image.png

可以看到控制台输出了Hello。

按照上面的方法我们可以获取Spring中的BeanFactory,并且可以根据BeanFactory获取索引的bean,以及进行相关的设置。

接下来我们回到激活Aware方法这一点上面来,也就是调用的invokeAwareMethods方法的源码。

private void invokeAwareMethods(String beanName, Object bean) {
   if (bean instanceof Aware) {
      if (bean instanceof BeanNameAware) {
         ((BeanNameAware) bean).setBeanName(beanName);
      }
      if (bean instanceof BeanClassLoaderAware) {
         ClassLoader bcl = getBeanClassLoader();
         if (bcl != null) {
            ((BeanClassLoaderAware) bean).setBeanClassLoader(bcl);
         }
      }
      if (bean instanceof BeanFactoryAware) {
         ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this);
      }
   }
}

不难看出就是对特殊的bean处理。

2.处理器的应用

BeanPostProcessor是Spring开放式架构中的一个必不可少的亮点,给用户权限去更改或者扩展Spring。

BeanPostProcessor使用的位置就是在initializeBean这个方法中,在调用客户自定义初始化方法前以及

自定义初始化方法后分别调用BeanPostProcessor的postProcessBeforeInitialization和

postProcessAfterInitialization方法。

3.激活自定义的init方法(invokeInitMethods)

除了init-method外,还有自定义的bean实现InitializingBean接口,并在afterPropertiesSet中实现自己的初始化业务逻辑。

init-method和afterPropertiesSet都在初始化bean的时候执行,顺序是afterPropertiesSet先执行,然后执行init-method。

/**
 * Give a bean a chance to react now all its properties are set,
 * and a chance to know about its owning bean factory (this object).
 * This means checking whether the bean implements InitializingBean or defines
 * a custom init method, and invoking the necessary callback(s) if it does.
 * 给bean一个反应的机会,现在它的所有属性都设置好了,  
 * 并有机会了解其所属的bean工厂(此对象)。  
 * 这意味着检查bean是否实现了InitializingBean或定义  
 * 一个自定义的init方法,并调用必要的回调(s)。  
 * @param beanName the bean name in the factory (for debugging purposes)
 * @param bean the new bean instance we may need to initialize
 * @param mbd the merged bean definition that the bean was created with
 * (can also be {@code null}, if given an existing bean instance)
 * @throws Throwable if thrown by init methods or by the invocation process
 * @see #invokeCustomInitMethod
 */
protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
      throws Throwable {
   // 首先会检查是否是InitializingBean,如果是就要调用afterPropertiesSet方法
   boolean isInitializingBean = (bean instanceof InitializingBean);
   if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
      if (logger.isDebugEnabled()) {
         logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
      }
      if (System.getSecurityManager() != null) {
         try {
            AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
               ((InitializingBean) bean).afterPropertiesSet();
               return null;
            }, getAccessControlContext());
         }
         catch (PrivilegedActionException pae) {
            throw pae.getException();
         }
      }
      else {
         // 属性初始化后处理
         ((InitializingBean) bean).afterPropertiesSet();
      }
   }

   if (mbd != null && bean.getClass() != NullBean.class) {
      String initMethodName = mbd.getInitMethodName();
      if (StringUtils.hasLength(initMethodName) &&
            !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
            !mbd.isExternallyManagedInitMethod(initMethodName)) {
         // 调用自定义初始化方法
         invokeCustomInitMethod(beanName, bean, mbd);
      }
   }
}

最后一个问题如果缓存中没有bean时会怎么办?

一般而言会先从缓存中去获取bean,如果缓存不存在已经加载的单例bean时,就需要从头开始bean的加载过程了

在Spring中是通过getSingleton的重载方法实现的bean的加载过程

源码如下:

/**
 * 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
 */
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {
   Assert.notNull(beanName, "Bean name must not be null");
   //全局变量需要同步
   synchronized (this.singletonObjects) {
      //先检查对应的bean是否已经加载过,因为singleton模式其实就是复用已创建的bean
      Object singletonObject = this.singletonObjects.get(beanName);
      //如果为空才进行singleton的bean的初始化
      if (singletonObject == null) {
         if (this.singletonsCurrentlyInDestruction) {
            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 + "'");
         }
         beforeSingletonCreation(beanName);
         boolean newSingleton = false;
         boolean recordSuppressedExceptions = (this.suppressedExceptions == null);
         if (recordSuppressedExceptions) {
            this.suppressedExceptions = new LinkedHashSet<>();
         }
         try {
            // 初始化bean
            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;
            }
            afterSingletonCreation(beanName);
         }
         if (newSingleton) {
            //加入缓存
            addSingleton(beanName, singletonObject);
         }
      }
      return singletonObject;
   }
}

可看到,通过这一步创建bean之后,最后会将bean实例加入缓存。

上述方法使用了回调方法,目的使程序在单例的创建前后做些扩展操作。

真正获取单例bean的方法并不在此方法中,其实现逻辑是在ObjectFactory类型的实例singletonFactory中
实现的。

image.png

该方法做了一下几件事:

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

2.若没有加载,则记录beanName为正在加载状态。

3.加载单例前记录加载状态。

beforeSingletonCreation方法虽然里面没有任何实现,但是非常重要,

/**
 * Callback before singleton creation.
 * 创建单例之前的回调。
 * <p>The default implementation register the singleton as currently in creation.
 * @param beanName the name of the singleton about to be created
 * @see #isSingletonCurrentlyInCreation
 */
protected void beforeSingletonCreation(String beanName) {
   if (!this.inCreationCheckExclusions.contains(beanName) && !this.singletonsCurrentlyInCreation.add(beanName)) {
      throw new BeanCurrentlyInCreationException(beanName);
   }
}

它做了一个操作:记录加载状态。

通过this.singletonsCurrentlyInCreation.add(beanName)将当前正要创建的bean记录到缓存中

这样便可以对循环依赖进行检测。

4.通过调用参数传入的ObjectFactory的个体Object方法实例化bean。

5.加载单例后的处理方法调用。afterSingletonCreation

和步骤3类似,当bean加载结束后需要移除缓存中对该bean的正在加载状态记录。

/**
 * Callback after singleton creation.
 * 创建单例之后的回调。
 * 当bean加载结束后需要移除缓存中对该bean的正在加载状态记录。
 * <p>The default implementation marks the singleton as not in creation anymore.
 * @param beanName the name of the singleton that has been created
 * @see #isSingletonCurrentlyInCreation
 */
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过程中所记录的各种辅助状态。

/**
 * Add the given singleton object to the singleton cache of this factory.
 * 将给定的单例对象添加到该工厂的单例缓存中。  
 * 将结果记录到缓存中并删除加载bean过程中所记录的各种辅助状态
 * <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);
   }
}

7.返回处理结果

至此我们也知道,并没有对bean加载的功能进行详细的了解,上面说到实现逻辑是在ObjectFactory类型的实例singletonFactory中,我们反推参数的获取,可以得到如下的代码:

sharedInstance = getSingleton(beanName, () -> {
   try {
      return createBean(beanName, mbd, args);
   }
   catch (BeansException ex) {
      // Explicitly remove instance from singleton cache: It might have been put there
      // eagerly by the creation process, to allow for circular reference resolution.
      // Also remove any beans that received a temporary reference to the bean.
      destroySingleton(beanName);
      throw ex;
   }
});

ObjectFactory的核心部分其实只是调用了createBean方法,还需要深入createBean方法才能得出最终的结果。

写在后面的话

至此在上一篇文章中提到的3个问题,相信到现在都已经了答案。

但是是不是总感觉查了一点,还是不够透彻,不慌我们在最后一篇中就彻底弄清楚。

下一篇我们会介绍下spring如何从bean的实例中获取对象

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值