• Spring Bean 的生命周期了解么?


    Spring Bean 的生命周期基本流程

    一个Spring的Bean从出生到销毁的全过程就是他的整个生命周期,

    img

    整个生命周期可以大致分为3个大的阶段 :

    • 创建

    • 使用

    • 销毁

    还可以分为5个小步骤 :

    实例化(Bean的创建) , 初始化赋值, 注册Destruction回调 , Bean的正常使用 以及 Bean的销毁

    Bean的创建和初始化赋值是分开的

    具体代码实现 :

    Spring容器在进行实例化的时候,会将xml配置的< bean > 的信息封装成一个BeanDefinition对象, Spring根据BeanDefinition来创建Bean对象,里面有很多的属性来描述Bean

    • beanClassName : bean的类名

    • initMethodName : 初始化方法名称

    • properryValues : bean的属性值

    • scope : 作用域

    • lazyInit : 延迟初始化

    1. 实例化Bean(实例化阶段)

      • Spring容器首先创建Bean实例

      • 调用Bean的构造函数,来实例化Bean对象

        • Spring在这一步创建Bean实例。 主要代码在AbstractAutowireCapableBeanFactory类中的createBeanInstance方法中实现

          就是先确保这个Bean对应的类已经被加载,然后确保他是public的,然后如果有工厂方法,则直接调用工厂方法创建Bean,如果没有的话就调用它的构造方法来创建这个Bean.

          这里需要注意的是 ,在Spring的完整Bean创建和初始化流程中,容器会在调用createBeanInstance之前检查Bean定义的作用域。如果是Singleton,容器会在其内部单例缓存中查找现有实例。如果实例已经存在,他将被重用;如果不存在,才会调用createBeanInstance来创建新的实例;

    2. (依赖注入)设置属性值(初始化阶段)

      • Spring容器注入必要的属性到Bean中

        • populateBean方法是Spring Bean生命周期中的一个关键部分,负责将属性值应用到新创建的Bean实例。他处理了自动装配,属性注入,依赖检查等多个方面 . 就是把各种属性进行初始化

    3. 检查Aware

      • 如果Bean实现了BeanNameAware , BeanClassLoaderAware等这些Aware接口, Spring容器会调用它们

        • BeanNameAware :通过这个接口,Bean可以获取到自己在Spring容器中的名字。这对于需要根据Bean的名称某些操作的常见很有用

        • ApplicationContextAware: 获取ApplicationContext对象;

        • BeanFactoryAware : 通过这个接口可以获取对BeanFactory的引用,获得对BeanFactory的访问权限

    4. 调用BeanPostProcessor前置处理方法 (初始化之前进行回调)

      • 在Bean初始化之前, 允许自定义的BeanPostProcessor对Bean实例进行处理,如修改Bean的状态. BeanPostProcessor的postProcessBeforeInitialization方法会在此时被调用

    5. 执行初始化方法

      1. 调用InitializingBean的afterPropertiesSet方法

        • 提供一个机会, 在所有Bean属性设置完成后进行初始化操作, 如果Bean实现了InitializingBean接口, afterPropertiesSet方法会被调用

        • 主要作用就是帮助我们在Bean的初始化前添加一些自己的逻辑处理,Spring内置了很多BeanPostProcessor,我们也可以定义一个或者多个BeanPostProcessor接口的实现,然后注册到容器中;

      2. 调用自定义init-method方法(初始化方法)

        • 提供一种配置方式, 在xml配置中指定Bean的初始化方法. 如果Bean在配置文件中定义了初始化方法,那么该方法就会被调用

    6. 调用BeanPostProcessor的后置处理方法 (Spring中对类进行增强的时候(AOP),就会使用后置处理器) --> AOP底层使用了动态代理和CGLB动态代理

      • 在Bean初始化之后,再次允许BeanPostProcessor对Bean进行处理. BeanPostProcessor的postProcessAfterInitialization方法会在此时被调用

    7. 注册Destruction回调

      • 如果Bean实现了DIsposableBean接口或者bean定义中指定了自定义的销毁方法,Spring容器会为这些Bean注册一个销毁回调,确保在容器关闭的时候能够正确的清理资源

    8. Bean准备就绪(Bean的使用阶段)

      • 此时,Bean已经完全初始化,可以开始处理应用程序的请求了

    9. 调用DisposableBean的destroy方法(Bean的销毁阶段)

      • 当容器关闭的时候, 如果Bean实现了DisposableBean接口, destroy方法会被调用

      • 在DisposableBeanAdapter的destroy方法中实现

    10. 调用自定义的destroy-method 当容器要进行关闭的时候,对象就会进入销毁阶段 ,最典型的就是,如果你使用了@PreDestroy注解,这个方法就是销毁方法 , Spring容器关闭的时候就会调用这个自定义的销毁方法

      • 如果Bean在配置文件中定义了销毁方法, 那么该方法就会被调用

      • 在DisposableBeanAdapter的destroy方法中实现

    可以看到, 整个Bean的创建的过程都依赖于AbstractAutowireCapableBeanFactory这个类,而销毁主要依赖于DisposableBeanAdapter这个类

    代码实践

    1. package com.sfx.spring6;
    2. import org.springframework.beans.factory.BeanNameAware;
    3. import org.springframework.beans.factory.DisposableBean;
    4. import org.springframework.beans.factory.InitializingBean;
    5. /**
    6. * Created with IntelliJ IDEA.
    7. * Description:
    8. * User: sfx
    9. * Date: 2024-02-20
    10. * Time: 21:20
    11. */
    12. public class CatDog implements BeanNameAware, InitializingBean, DisposableBean {
    13. private String name;
    14. public CatDog() {
    15. System.out.println("1. 实例化Bean");
    16. }
    17. public String getName() {
    18. return name;
    19. }
    20. public void setName(String name) {
    21. System.out.println("2. 执行了set方法, 设置相关属性");
    22. this.name = name;
    23. }
    24. public void myInit() {
    25. System.out.println("6. 执行了自定义初始化方法");
    26. }
    27. public void myDestroy() {
    28. System.out.println("10. 执行了自定义的销毁方法");
    29. }
    30. @Override
    31. public void setBeanName(String name) {
    32. System.out.println("3. 执行了 BeanNameAware");
    33. }
    34. @Override
    35. public void afterPropertiesSet() throws Exception {
    36. System.out.println("5. 执行afterPropertiesSet");
    37. }
    38. @Override
    39. public void destroy() throws Exception {
    40. System.out.println("9. 执行了DisposableBean");
    41. }
    42. }
    1. package com.sfx.spring6;
    2. import org.springframework.beans.factory.BeanNameAware;
    3. import org.springframework.beans.factory.DisposableBean;
    4. import org.springframework.beans.factory.InitializingBean;
    5. /**
    6. * Created with IntelliJ IDEA.
    7. * Description:
    8. * User: sfx
    9. * Date: 2024-02-20
    10. * Time: 21:20
    11. */
    12. public class CatDog implements BeanNameAware, InitializingBean, DisposableBean {
    13. private String name;
    14. public CatDog() {
    15. System.out.println("1. 实例化Bean");
    16. }
    17. public String getName() {
    18. return name;
    19. }
    20. public void setName(String name) {
    21. System.out.println("2. 执行了set方法, 设置相关属性");
    22. this.name = name;
    23. }
    24. public void myInit() {
    25. System.out.println("6. 执行了自定义初始化方法");
    26. }
    27. public void myDestroy() {
    28. System.out.println("10. 执行了自定义的销毁方法");
    29. }
    30. @Override
    31. public void setBeanName(String name) {
    32. System.out.println("3. 执行了 BeanNameAware");
    33. }
    34. @Override
    35. public void afterPropertiesSet() throws Exception {
    36. System.out.println("5. 执行afterPropertiesSet");
    37. }
    38. @Override
    39. public void destroy() throws Exception {
    40. System.out.println("9. 执行了DisposableBean");
    41. }
    42. }
    1. package com.sfx.spring6;
    2. import org.springframework.context.ApplicationContext;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. /**
    5. * Created with IntelliJ IDEA.
    6. * Description:
    7. * User: sfx
    8. * Date: 2024-02-20
    9. * Time: 21:23
    10. */
    11. public class App {
    12. public static void main(String[] args) {
    13. ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean.xml");
    14. CatDog bean = applicationContext.getBean(CatDog.class);
    15. String name = bean.getName();
    16. System.out.println("8. 使用了Bean , " + name);
    17. ((ClassPathXmlApplicationContext) applicationContext).close();
    18. }
    19. }
    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans
    5. http://www.springframework.org/schema/beans/spring-beans.xsd">
    6. <bean id = "catDog" class="com.sfx.spring6.CatDog" init-method="myInit" destroy-method="myDestroy">
    7. <property name="name" value="张三">property>
    8. bean>
    9. <bean id="processor" class="com.sfx.spring6.Processor">
    10. bean>
    11. beans>

    项目中会用到哪些流程呢 ? 

    我们在项目中一般等到项目初始化完成后立马执行一些动作, 比如RocketMQ开启消费者,还有等等我们需要在项目初始化完成之后就要执行一些动作,我们就可以调用 InitializingBean 的afterPropertiesSet方法

    好的记忆方法

    我们可以给面试官这么讲解, SpringBean的生命周期分为三个大的阶段 

    • 创建
    • 使用
    • 销毁

    如果划分为具体的细的5个阶段 :

    • 实例化
    • 初始化(依赖注入)
    • 注册Destruction的回调
    • Bean的使用
    • Bean的销毁

    然后我们再来了解每一个阶段都要做哪些事情

    • 实例化
      • 首先会根据扫描我们写的xml,将一些属性设置到BeanDefination对象上,然后调用构造方法创建出一个Bean
    • 初始化
      • 给Bean设置属性(此时会调用bean的set方法)
      • 检查有没有实现以aware结尾的相关接口
        • BeanNameAware :通过这个接口,Bean可以获取到自己在Spring容器中的名字。这对于需要根据Bean的名称某些操作的常见很有用

        • ApplicationContextAware: 获取ApplicationContext对象;

        • BeanFactoryAware : 通过这个接口可以获取对BeanFactory的引用,获得对BeanFactory的访问权限

      • 执行初始化前置方法

      • 执行初始化方法  (有两个, 首先先会调用 InitializingBean 的afterPropertiesSet方法,然后会调用自己定义的初始化方法)

      • 执行初始化后置方法

      • 注册Destruction的回调

        • 如果Bean实现了DIsposableBean接口或者bean定义中指定了自定义的销毁方法,Spring容器会为这些Bean注册一个销毁回调,确保在容器关闭的时候能够正确的清理资源

      • 开始使用Bean

      • 调用DisposableBean的destroy方法(Bean的销毁阶段)

        • 当容器关闭的时候, 如果Bean实现了DisposableBean接口, destroy方法会被调用

        • 在DisposableBeanAdapter的destroy方法中实现

      • 调用自定义的destroy-method 当容器要进行关闭的时候,对象就会进入销毁阶段 ,最典型的就是,如果你使用了@PreDestroy注解(对于SpringBoot),这个方法就是销毁方法 , Spring容器关闭的时候就会调用这个自定义的销毁方法

        • 如果Bean在配置文件中定义了销毁方法, 那么该方法就会被调用

        • 在DisposableBeanAdapter的destroy方法中实现

    对于SpringBoot而言,如果你想要在实例化和依赖注入完成后进行初始化操作,可以加@PostConstruct注解 ,当然也可以使用 InitializingBean 的afterPropertiesSet方法

    如果你想要自定义销毁方法 , 可以加 @PreDestroy注解

    下次分享再见~~~

  • 相关阅读:
    十、【图框工具组】
    leetcode 每日一题复盘(10.9~10.15)
    计算机竞赛保研经验分享 - 项目推荐
    记一次SpringBoot中Service层未注入排查
    MyBatisPlus-条件构造器/分页/多数据源/MyBatisX插件(生成代码)
    icon免费网址
    在 Linux 操作系统中使用locate 命令快速定位文件和目录
    抠图,水印-----ps
    字节前端实习的两道算法题,看看强度如何
    SpringBoot2.0---------------4、SpringBoot底层注解之添加组件
  • 原文地址:https://blog.csdn.net/m0_61210742/article/details/136200216