Spring-Bean的生命周期

一.生命流程

要彻底搞清Spring的生命周期,首先要牢牢记住四个阶段。

  1. 实例化
  2. 属性赋值
  3. 初始化
  4. 销毁

源码如下,能证明实例化,属性赋值和初始化这三个生命周期的存在。本文中的Spring源码将会忽略无关部分,便于理解:

// 忽略了无关代码
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final @Nullable Object[] args)
      throws BeanCreationException {

   // Instantiate the bean.
   BeanWrapper instanceWrapper = null;
   if (instanceWrapper == null) {
       // 实例化阶段!
      instanceWrapper = createBeanInstance(beanName, mbd, args);
   }

   // Initialize the bean instance.
   Object exposedObject = bean;
   try {
       // 属性赋值阶段!
      populateBean(beanName, mbd, instanceWrapper);
       // 初始化阶段!
      exposedObject = initializeBean(beanName, exposedObject, mbd);
   }

   
   }

对bean的生命周期的四个阶段展开更详细的描述:

bean实例化过程

  1. 实例化bean对象。
  2. 将配置文件中配置的属性填充到刚刚创建的bean对象中。
  3. 检查bean对象是否实现了Aware一类的接口,如果实现了则把相应的依赖设置到bean对象中。比如如果bean实现了BeanFactoryAware接口,Spring容器在实例化bean的过程中,会将BeanFactory容器注入到bean中。
  4. 调用BeanPostProcessor前置处理方法,即 postProcessBeforeInitialization(Object bean, String beanName)。
  5. 检查bean对象是否实现了InitializingBean接口,如果实现了,则调用afterPropertiesSet方法。或者检查配置文件中是否配置了init-method属性,如果配置了,则去调用init-method属性配置的方法。
  6. 调用 BeanPostProcessor 后置处理方法,即 postProcessAfterInitialization(Object bean, String beanName)。我们所熟知的 AOP 就是在这里将 Adivce 逻辑织入到 bean 中的。
  7. 注册Destruction相关回调方法。
  8. bean处于就绪状态,可以使用了。
  9. 应用上下文被销毁,调用注册Destruction相关方法。如果 bean 实现了 DispostbleBean 接口,Spring 容器会调用 destroy 方法。如果在配置文件中配置了 destroy 属性,Spring 容器则会调用 destroy 属性对应的方法。

二.详细细节和扩展点

2.1 设置属性

流程的第二步-设置属性,在这一步中,对于普通类型的属性,例如String,Integer等,比较容易处理,直接设置即可。但是如果某个bean对象依赖另一个bean对象,此时就不能直接设置了。Spring容器首先先要去实例化bean依赖的对象,实例化好了才能设置到当前bean中。

还有对循环依赖的处理,可以看:Spring IOC源码-循环依赖的解决方法

2.2 影响多个Bean的接口

实现了这些接口的Bean会切入到多个Bean的生命周期中。这些接口功能非常强大,Spring内部扩展也常用这些接口,例如自动注入以及AOP实现都与他们有关。

  • BeanPostProcessor
  • InstantiationAwareBeanPostProcessor

这两兄弟可能是Spring扩展中最重要的两个接口!InstantiationAwareBeanPostProcessor作用于实例化阶段的前后,BeanPostProcessor作用于初始化阶段的前后。正好和第一、第三个生命周期阶段对应。通过图能更好理解:

InstantiationAwareBeanPostProcessor实际上继承了BeanPostProcessor接口。InstantiationAwareBeanPostProcessor源码分析:

  • postProcessBeforeInstantiation调用点,忽略无关代码:
@Override
    protected Object createBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
            throws BeanCreationException {

        try {
            // Give BeanPostProcessors a chance to return a proxy instead of the target bean instance.
            // postProcessBeforeInstantiation方法调用点,在doCreateBean之前调用,也就是bean实例化之前调用
            Object bean = resolveBeforeInstantiation(beanName, mbdToUse);
            if (bean != null) {
                return bean;
            }
        }
        
        try {   
            // 上文提到的doCreateBean方法,可以看到
            // postProcessBeforeInstantiation方法在创建Bean之前调用
            Object beanInstance = doCreateBean(beanName, mbdToUse, args);
            if (logger.isTraceEnabled()) {
                logger.trace("Finished creating instance of bean '" + beanName + "'");
            }
            return beanInstance;
        }
        
    }
  • postProcessAfterInstantiation调用点,忽略无关代码:
protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {

   // Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
   // state of the bean before properties are set. This can be used, for example,
   // to support styles of field injection.
   boolean continueWithPropertyPopulation = true;
    // InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()
    // 方法作为属性赋值的前置检查条件,在属性赋值之前执行,能够影响是否进行属性赋值!
   if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
      for (BeanPostProcessor bp : getBeanPostProcessors()) {
         if (bp instanceof InstantiationAwareBeanPostProcessor) {
            InstantiationAwareBeanPostProcessor ibp = (InstantiationAwareBeanPostProcessor) bp;
            if (!ibp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
               continueWithPropertyPopulation = false;
               break;
            }
         }
      }
   }

   // 忽略后续的属性赋值操作代码
}

关于BeanPostProcessor执行阶段的源码穿插在下文Aware接口的调用时机分析中,因为部分Aware功能的就是通过他实现的!只需要先记住BeanPostProcessor在初始化前后调用就可以了

2.3 只调用一次的接口

2.3.1 接口分类

这一类接口的特点是功能丰富,常用于用户自定义扩展。这个有可以分为两类:

  1. Aware类型的接口,就是让我们可以拿到Spring中的一些资源。
  2. 生命周期接口

Aware接口的分组:

Aware Group1:

  1. BeanNameAware
  2. BeanClassLoaderAware
  3. BeanFactoryAware

 Aware Group2:

  1. EnvironmentAware
  2. EmbeddedValueResolverAware 这个知道的人可能不多,实现该接口能够获取Spring EL解析器,用户的自定义注解需要支持spel表达式的时候可以使用,非常方便。
  3. ApplicationContextAware(ResourceLoaderAware\ApplicationEventPublisherAware\MessageSourceAware)

2.3.2 Aware调用时机源码分析

下面代码,忽略了部分无关代码。代码位置就是initializeBean方法,这也说明了Aware是在初始化阶段之前被调用。

    // 见名知意,初始化阶段调用的方法
    protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {

        // 这里调用的是Group1中的三个Bean开头的Aware
        invokeAwareMethods(beanName, bean);

        Object wrappedBean = bean;
        
        // 这里调用的是Group2中的几个Aware,
        // 而实质上这里就是前面所说的BeanPostProcessor的调用点!
        // 也就是说与Group1中的Aware不同,这里是通过BeanPostProcessor(ApplicationContextAwareProcessor)实现的。
        wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
      
        invokeInitMethods(beanName, wrappedBean, mbd);
        // BeanPostProcessor的另一个调用点
        wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);

        return wrappedBean;
    }

可以看到并不是所有的Aware接口都使用同样的方式调用。Bean××Aware都是在代码中直接调用的,而ApplicationContext相关的Aware都是通过BeanPostProcessor#postProcessBeforeInitialization()实现的。

BeanPostProcessor的调用时机也能在这里体现,包围住invokeInitMethods方法,也就说明了在初始化阶段的前后执行。

2.3.3 两个简单生命周期接口

实例化和属性赋值都是Spring帮我们做的,能够自己实现的有初始化和销毁两个生命周期阶段。

  • InitializingBean 对应生命周期的初始化阶段,在上面源码的invokeInitMethods(beanName, wrappedBean, mbd);方法中调用。
    有一点需要注意,因为Aware方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用Aware接口获取的资源,这也是我们自定义扩展Spring的常用方式。
    除了实现InitializingBean接口之外还能通过注解或者xml配置的方式指定初始化方法,至于这几种定义方式的调用顺序其实没有必要记。因为这几个方法对应的都是同一个生命周期,只是实现方式不同,我们一般只采用其中一种方式。
  • DisposableBean 类似于InitializingBean,对应生命周期的销毁阶段,以ConfigurableApplicationContext#close()方法作为入口,实现是通过循环取所有实现了DisposableBean接口的Bean然后调用其destroy()方法 。感兴趣的可以自行跟一下源码。


参考:请别再问Spring Bean的生命周期了!


 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值