文章

Bean生命周期

Bean 生命周期流程

Bean生命周期

在Spring 容器启动过程中,会调用AbstractApplicationContext类中refresh(),该方法是 Spring 容器启动的核心方法。其中,Spring Bean 的创建就是在该方法中的finishBeanFactoryInitialization()中进行的,在 Spring Bean 的创建之前,其实 Spring 在refresh()方法中。

  1. 生成BeanDefinition,并存储到一个 beanDefinitionMap对象中。Spring 容器启动时,会根据配置的扫描路径得到所有的 class 文件资源;然后通过 ASM 技术将每个文件资源解析为MetadataReader对象;最后根据MetadataReader对象生成BeanDefinition,并存储到beanDefinitionMap对象中。
1
private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
  1. 合并BeanDefinition

    为什么要做合并操作 ?

    是基于Spring 中的父子 BeanDefinitiong 功能点考虑。

  2. 将 Spring 容器中内置的 BeanPostProcessor和扫描得到的自定义所有的BeanPostProcessor添加到beanPostProcessors集合对象中。

1
private final List<BeanPostProcessor> beanPostProcessors = new BeanPostProcessorCacheAwareList();

基于上述三点,Spring 容器就可以根据合并后的 BeanDefinition进行 Bean 对象的创建。Spring 容器 Bean 创建的源码主要是:AbstractAutowireCapableBeanFactorycreateBean()doCreateBean()initializeBean()等方法。

Bean创建

1. 实例化前:

  • 在Bean 的实例化之前,Spring 提供了一个 InstantiationAwareBeanPostProcessor的扩展点,可以通过该扩展点,在 Bean 的实例化之前或者实例化之后完成相应的业务逻辑。

例:自定义了一个扩展点,该扩展点通过使用@Component注解修饰,并通过实现 InstantiationAwareBeanPostProcessor接口以及实现 postProcessBeforeInstantiation()方法,该方法就会在Bean 的实例化之前被调用。如果我们在postProcessBeforeInstantiation()中返回值不为 null,接下来 userService的创建就不会在经过后面完整的生命周期了,而是会直接跳到初始化后的执行阶段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {

@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
  // 如果 beanName 是 "user",则提前返回一个 Bean 实例,阻止正常的实例化过程
  if ("user".equals(beanName)) {
      System.out.println("在实例化之前 " + beanName);
      // 这里可以创建一个代理对象或者修改后的实例来替代原始的 Bean 实例
      return new User(); // User 是一个自定义类
  }
  return null; // 继续正常的实例化过程
}
}

@Component
public class User {
public User() {
  System.out.println("通过默认构造函数创建的 User 实例");
}

public void doSomething() {
  System.out.println("User 做点什么");
}
}
@Test
public void testAppConfig() {
  AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext("com.muzhi.pojo");
  // 注册配置类或Bean定义
  context.register(AppConfig.class);
  User user = context.getBean(User.class);
  user.doSomething();
  context.close();
}

2. 实例化:

  • 接下来就可以根据BeanDefinition实例化 Bean 对象了,该阶段的主要执行逻辑如下:
    • 首先判断该BeanDefinition中是否设置了Supplier,如果设置了则调用Supplier的 get() 获取对象;
    • 如果没有设置Supplier,则会检查该BeanDefinition中是否设置了 factoryMethod,如果设置了,则会调用工厂方法获取对象。
    • 如果也没有设置工厂方法,则会执行推断构造方法,根据推断处理的构造方法示例化 Bean 对象。

3. BeanDefinition 的后置处理:

  • 实例化 Bean 对象之后,就可以为其属性赋值,不过在属性赋值之前,Spring 提供了一个扩展点:MergedBeanDefinitionPostProcessor。可以通过该扩展点对此时的BeanDefinition对象进行加工。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

public class PostProcessorDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
        context.register(PostProcessorConfig.class);
        context.refresh();

        // 获取处理后的Bean
        MyBean myBean = context.getBean(MyBean.class);
        System.out.println("Custom property value: " + myBean.getCustomProperty());

        context.close();
    }
}

@Configuration
class PostProcessorConfig {

    @Bean
    public static MyBeanDefinitionPostProcessor myBeanDefinitionPostProcessor() {
        return new MyBeanDefinitionPostProcessor();
    }
}

class MyBeanDefinitionPostProcessor implements BeanDefinitionPostProcessor {

    @Override
    public void postProcessBeanDefinition(BeanDefinition bd, String beanName) {
        if ("MyBean".equals(beanName)) {
            // 确保是一个GenericBeanDefinition,以支持设置额外的属性
            GenericBeanDefinition gbd = (GenericBeanDefinition) bd;
            gbd.getPropertyValues().add("customProperty", "Hello, World!");
        }
    }

    @Override
    public void postProcessMergedBeanDefinition(BeanDefinition bd, String beanName) {
        // 可以在Bean定义合并后进行进一步的处理
    }
}

class MyBean {
    private String customProperty;

    public String getCustomProperty() {
        return customProperty;
    }

    // 其他方法...
}

4. 实例化后:

  • BeanDefinition的后置处理之后,Spring 又提供了一个和步骤 1 中完全相同的扩容点:InstantiationAwareBeanPostProcessor。通过该扩展点的postProcessAfterInstantiation()也可以实现在 Bean 的实例化之后完成业务逻辑的功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 可以在 Bean 初始化之前执行一些操作
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 可以在 Bean 初始化之后执行一些操作
        if ("myBean".equals(beanName)) {
            // 假设 MyBean 有一个 "setName" 方法
            ((MyBean) bean).setName("Processed by BeanPostProcessor");
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
        // Bean 实例化之后、属性填充之前的处理
        if ("myBean".equals(beanName)) {
            System.out.println("MyBean instance created: " + bean);
            // 可以在这里修改 Bean 实例的某些属性或执行其他逻辑
            // 注意:此时 Bean 的属性还未设置
        }
        return bean;
    }
}

@Component
class MyBean {
    private String name;

    // 假设有一个构造器
    public MyBean() {
    }

    // 普通方法
    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

5. 自动注入:

  • Spring 自动注入

6. 处理属性:

  • 该步骤也是通过InstantiationAwareBeanPostProcessor扩展来实现的,它会处理@Autowired@Resource@Value等注解。通过实现该扩展点的postProcessProperties()

7. Aware 接口回调:

  • 依赖注入完成后,Spring会判断该对象是否实现了 BeanNameAwareBeanClassLoaderAwareBeanFactoryAware接口。
  • 如果实现了,Spring就会相应的调用setBeanName()setClassLoader()setBeanFactory()方法并传入相应的 BeanNameBeanClassLoaderBeanFactory参数。

8. 初始化前:

  • 该步骤会遍历BeanPostProcessors对象,并执行它们的postProcessBeforeInitialization()方法。
  • 其中,InitDestroyAnnotationBeanPostProcessor后置处理器会在该步骤中执行被@PostConstruct注解声明的方法;
  • ApplicationContextAwareProcessor后置处理器会在该步骤执行一系列Aware接口的回调;
  • 当,如果自定义了 BeanPostProcessor后置处理器并实现了postProcessBeforeInitialization()方法,也会在该步骤中被调用。

9. 初始化:

  • 该步骤会先判断当前 Bean 对象是否实现了InitializingBean接口,如果实现了,则会调用当前对象中的afterPropertiesSet()方法。
  • 另外,如果配置了初始化方法,也会在此步骤中调用。

10. 初始化后:

  • 该步骤会遍历BeanPostProcessors对象,并执行postProcessAfterInitialization()方法。
  • 也可以对 Bean 进行最终处理,如:AOP 的实现。

Bean使用

Spring 中 Bean 对象创建完成后,会放入到singletonObjects的Map对象中,称为单例池;接下来使用Bean 对象,直接从单例池中获取。

1
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

Bean销毁

AbstractAutowireCapableBeanFactorydoCreateBean()方法中,执行完Bean 的初始化方法后,会执行registerDisposableBeanIfNecessary(),该方法的主要作用就是判断当前Bean 对象是否是一个DisposableBean,如果是则会把当前Bean包装为DisposableBeanAdapter适配器对象并放入到一个disposableBeans的 Map 对象中缓存起来。

其中,判断当前 Bean 对象中是否是一个DisposableBean的逻辑如下:

  1. 当前 Bean 对象是否实现了DisposableBean接口;

  2. 当前 Bean 对象是否实现了AutoCloseable接口;

  3. 当前 Bean 对象是否配置了destriyMethod()方法;

  4. 遍历所有的DestructionAwareBeanPostProcessor后置处理器,并通过requiresDestruction()方法进行判断,当前 Bean 对象是否返回**true ** 。

    注意: InitDestroyAnnotationBeanPostProcessor后置处理器的requiresDestruction()方法会判端当前 Bean 对象中是否使用@PreDestroy注解,如果存在,也会返回true

缓存了DisposableBean对象后,Spring 中的 Bean对象在什么时候会被销毁?

在Spring 容器关闭时,有两中方式进行关闭Spring容器:

1
2
3
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext("com.muzhi.pojo");
ac.close();// 方式一
ac.registerShutdownHook();// 方式二

方式一:立即关闭Spring容器。

方式二:调用 JDK 关闭钩子来执行关闭容器操作。

Spring 容器关闭,就会销毁所有的单例 Bean。在单例Bean销毁之前,会先遍历DisposableBeans对象,并调用DisposableBeandestroy()方法。所谓单例 Bean 的销毁,无非就是从单例池等缓存对象移除Bean对象。

本文由作者按照 CC BY 4.0 进行授权