Spring IOC源码分析-Bean的生命周期

910 阅读4分钟

这是我参与8月更文挑战的第28天,活动详情查看:8月更文挑战

Spring 源码分析系列

前言

Bean的生命周期是面试Spring框架必问的考点, 在 BeanFactory 接口注释上就描述了, 一个Bean对象从工厂生产到最后消亡的全部过程. 我们不看源码其实也可以思考一下, 一个对象重创建到消亡需要做些什么?

我们可能会想到首先当然是创建对象, 实例化当然是调用构造函数, 实例化之后, 然后我们需要去做一些初始化的操作, 比如设置一些非构造函数属性的值, 当对象用完了然后就是销毁. 当然Spring Bean不一样因为会存在Bean的依赖, 在初始化之前会多一步属性填充,

Spring Bean的生命周期其实也是对象创建的过程, 可以划分为4个阶段和多个扩展点

Bean的生命周期.png

Bean的生命周期

Spring 源码注释上已经描述了Bean的生命周期 image.png

Bean销毁的过程 image.png

Spring Bean的生命周期分为四个阶段多个扩展点。扩展点又可以分为影响多个Bean影响单个Bean

1.1 四个阶段

  • 实例化 Instantiation
  • 属性赋值 Populate
  • 初始化 Initialization
  • 销毁 Destruction

源码分析: 前三个阶段的源码, 都在 AbstractAutowireCapableBeanFactory #doCreateBean 方法实现的.

createBeanInstance 实例化 image.png

populateBean 属性注入和initializeBean 初始化Bean方法 image.png 上面实例化Bean的方法是在getBean()方法中调用的, 而getBean是在finishBeanFactoryInitialization方法中调用的,用来实例化单例非懒加载Bean.

销毁Bean阶段: 是在容器关闭时调用的,详见 ConfigurableApplicationContext#close()

1.2 生命周期扩展点

生命周期扩展点非常多,按照影响Bean的范围分类

1.2.1 影响多个Bean

  1. BeanPostProcessor
  2. InstantiationAwareBeanPostProcessor

InstantiationAwareBeanPostProcessor作用于实例化阶段的前后,BeanPostProcessor作用于初始化阶段的前后。

1.2.2 影响单个Bean

1. Aware接口, 分为两组Aware Group1 和Aware Group2

一堆的Aware接口, Aware是一个具有标识作用的超级接口,实现该接口的bean是具有被spring 容器通知的能力的,而被通知的方式就是通过回调。也就是说:直接或间接实现了这个接口的类,都具有被spring容器通知的能力。

1.1 Aware Group1

  • BeanNameAware
  • BeanClassLoaderAware
  • BeanFactoryAware

Aware Group2

  • EnvironmentAware
  • EmbeddedValueResolverAware
  • ApplicationContextAware( 这个接口又包含了ResourceLoaderAware,ApplicationEventPublisherAwareMessageSourceAware)

EmbeddedValueResolverAware 该接口能够获取Spring EL解析器,用户的自定义注解需要支持spel表达式的时候可以使用,非常方便。

ApplicationContextAware ResourceLoaderAware,ApplicationEventPublisherAware,MessageSourceAware 返回值实质上都是当前的ApplicationContext对象,因为ApplicationContext是一个复合接口.

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
      MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
      // ....
      }

Aware扩展点调用时机源码分析

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 {
      // 1. 调用的是Group1中的三个Bean开头的Aware
      invokeAwareMethods(beanName, bean);
   }

   Object wrappedBean = bean;
   if (mbd == null || !mbd.isSynthetic()) {
      // 这里调用的是Group2中的几个Aware,
      // 而实质上这里就是前面所说的BeanPostProcessor的调用点
      // 与Group1中的Aware不同,这里是通过BeanPostProcessor(ApplicationContextAwareProcessor)实现的。
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
   }

   try {
      // 初始化方法
      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;
}

2. 生命周期

  1. InitializingBean
  2. DisposableBean

InitializingBean 顾名思义,是初始化Bean相关的接口。

image.png afterPropertiesSet()方法是在初始化过程中被调用的。 InitializingBean 对应生命周期的初始化阶段,在上面源码的invokeInitMethods(beanName, wrappedBean, mbd);方法中调用。

三种实现指定初始化方法的方法:

  1. 使用@PostConstruct注解,该注解作用于void方法上

  2. 在配置文件中配置init-method方法

<bean id="User" class="com.br.spring.demo.dto.User" init-method="init2">
   <property name="name" value="boren"></property>
</bean>
  1. 实现InitializingBean接口
@Component
public class UserBean implements InitializingBean {

   private String name;

   public String getName() {
      return name;
   }

   public void setName(String name) {
      this.name = name;
   }

   //1.使用PostConstruct注解
   @PostConstruct
   public void init(){
      System.out.println("执行 init方法");
   }

   //2.在xml配置文件中配置init-method方法
   public void init2(){
      System.out.println("执行init2方法 ");
   }

   //3.实现InitializingBean接口
   public void afterPropertiesSet() throws Exception {
      System.out.println("执行init3方法");
   }
}

最后

Spring 生命周期的四个阶段, 实例化, 属性注入, 初始化, 销毁和Spring 核心扩展点 Aware 和 生命周期接口 InitializingBean , DisposableBean