描述一下 Spring Bean 的生命周期 ?

Spring Bean 的生命周期是指 Bean 从创建、初始化、使用到销毁的完整过程,核心由 Spring 容器全程管理,主要可分为 4 个核心阶段,关键节点需结合初始化/销毁方法和后置处理器。

spring Bean流程图:

1. Bean 的创建阶段

css 复制代码
容器通过 XML 配置、注解(@Component 等)或 Java 配置类 扫描并定位 Bean 的定义信息(BeanDefinition)。

根据 Bean 的作用域(默认单例),容器在启动时(单例 Bean)或首次获取时(原型 Bean),通过反射调用 Bean 的 无参构造方法 创建实例对象。

2. Bean 的初始化阶段(核心)

初始化是 Bean 功能完善的关键步骤,按顺序执行以下操作:

typescript 复制代码
1.设置属性(依赖注入):容器将 Bean 依赖的其他对象(如 @Autowired 标注的属性)注入到当前 Bean 中。

2.调用Aware接口方法:若 Bean 实现了 BeanNameAware、BeanFactoryAware 等接口,容器会主动调用接口方法,传递 Bean 名称、BeanFactory 等容器信息(如 setBeanName(String name))。

3.调用BeanPostProcessor前置方法:容器中的 BeanPostProcessor 接口实现类,会调用 postProcessBeforeInitialization(Object bean, String beanName),对 Bean 进行初始化前的自定义处理(如AOP代理前置准备)。

4.执行自定义初始化方法:

若通过 XML 配置(init-method 属性)、注解(@PostConstruct)或实现 InitializingBean 接口(afterPropertiesSet() 方法)定义了初始化逻辑,容器会依次执行这些方法。

5.调用BeanPostProcessor后置方法:BeanPostProcessor 实现类调用 postProcessAfterInitialization(Object bean, String beanName),完成初始化后的最终处理(如生成AOP代理对象)。

至此,Bean 已完全初始化,可被容器或业务代码获取并使用。

3. Bean 的使用阶段

初始化完成的 Bean 存储在容器中,根据作用域提供服务:

scss 复制代码
单例 Bean:全程只有一个实例,容器启动后持续存在,供多次获取和使用。

原型 Bean:每次调用 getBean() 都会创建新实例,使用后由 JVM 垃圾回收(Spring 不管理原型 Bean 的销毁)。

4. Bean 的销毁阶段(仅单例 Bean)

当 Spring 容器关闭(如应用停止)时,单例 Bean 会触发销毁流程:

scss 复制代码
1.若 Bean 实现 DisposableBean 接口,容器调用其 destroy() 方法。

2.执行自定义销毁方法:通过 XML 配置(destroy-method 属性)或注解(@PreDestroy)定义的销毁逻辑(如释放数据库连接、关闭线程池)。

3.销毁完成后,Bean 实例被 JVM 垃圾回收。

代码实例:

Book

csharp 复制代码
public class Book implements InitializingBean, DisposableBean, BeanNameAware, BeanFactoryAware, ApplicationContextAware {
    private String title;

    //空参
    public Book() {
        System.out.println("1.实例化 Book 对象");
    }

    //set
    public void setTitle(String title) {
        this.title = title;
        System.out.println("2.依赖注入(属性填充) 设置 Book 对象的 title 属性,title = " + title);
    }

    //get
    public String getTitle() {
        return title;
    }

    //初始化方法
    public void myInit() {
//        System.out.println("3.初始化方法 Book 对象");
        if (title == null) {
            title = "默认书籍"; // 如果没有设置标题,则使用默认标题
            System.out.println("3 初始化方法 Book 对象> 默认标题是:" + title);
        } else {
            System.out.println("3 初始化方法 Book 对象> 标题是:" + title);
        }
    }

    //销毁方法
    public void myDestroy() {
        System.out.println("5.销毁方法 Book 对象");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("2.9.初始化方法 Book 对象 -- afterPropertiesSet");
        if (title == null) {
            title = "默认书籍"; // 如果没有设置标题,则使用默认标题
//            System.out.println("4.1 初始化方法 Book 对象> 默认标题是:" + title);
        } else {
//            System.out.println("4.1 初始化方法 Book 对象> 标题是:" + title);
        }

    }

    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("2.2 设置 Bean 工厂为:" + beanFactory.getClass().getName());

    }

    public void setBeanName(String s) {
        System.out.println("2.1 设置 Bean 名称为:" + s);

    }

    public void destroy() throws Exception {
        System.out.println("4.9 销毁方法 Book 对象 -- DisposableBean");
        // 在这里可以执行一些清理操作,例如关闭资源等

    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("2.3 设置 ApplicationContext 为:" + applicationContext.getClass().getName());

    }
}

BookProcessor

typescript 复制代码
public class BookProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        // 在初始化之前执行
        if (bean instanceof Book) {
            System.out.println("2.5 -- Before Initialization: " + beanName);
        }
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        // 在初始化之后执行
        if (bean instanceof Book) {
            System.out.println("3.5 -- After Initialization: " + beanName);
        }
        return bean;
    }
}

spring.xml

xml 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    定义一个book bean-->
    <bean id="book" class="com.example.demo.bean.Book" init-method="myInit" destroy-method="myDestroy">
        <property name="title" value="Java编程思想"/>
    </bean>

    <!-- 定义一个BookProcessor bean -->
    <bean id="bookProcessor" class="com.example.demo.bean.BookProcessor"/>

</beans>

测试类

csharp 复制代码
 @Test
    public void test4() {
        // 测试类
        //通过注解的方式生成bean的测试
        ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        // 获取 book 对象
        Book book = context.getBean(Book.class);
        // 4.使用bean
//        System.out.println("8.使用Bean  Cat 对象,name = " + cat.getName());
        System.out.println("4.使用Bean  Book 对象,name = " + book.getTitle());
        // 关闭容器
        ((ClassPathXmlApplicationContext) context).close();
        // 5.销毁 Cat 对象
        // 注意:在使用 ClassPathXmlApplicationContext 时,销毁方法会在 close() 方法调用时自动执行
    }

运行结果如下:

ini 复制代码
1.实例化 Book 对象
2.依赖注入(属性填充) 设置 Book 对象的 title 属性,title = Java编程思想
2.1 设置 Bean 名称为:book
2.2 设置 Bean 工厂为:org.springframework.beans.factory.support.DefaultListableBeanFactory
2.3 设置 ApplicationContext 为:org.springframework.context.support.ClassPathXmlApplicationContext
2.5 -- Before Initialization: book
2.9.初始化方法 Book 对象 -- afterPropertiesSet
3 初始化方法 Book 对象> 标题是:Java编程思想
3.5 -- After Initialization: book
4.使用Bean  Book 对象,name = Java编程思想
4.9 销毁方法 Book 对象 -- DisposableBean
5.销毁方法 Book 对象
相关推荐
现在就干13 分钟前
Spring事务基础:你在入门时踩过的所有坑
java·后端
该用户已不存在25 分钟前
Gradle vs. Maven,Java 构建工具该用哪个?
java·后端·maven
JohnYan36 分钟前
Bun技术评估 - 23 Glob
javascript·后端·bun
二闹40 分钟前
聊天怕被老板发现?摩斯密码来帮你
后端·python
用户298698530141 小时前
# C#:删除 Word 中的页眉或页脚
后端
David爱编程1 小时前
happens-before 规则详解:JMM 中的有序性保障
java·后端
小张学习之旅1 小时前
ConcurrentHashMap
java·后端
PetterHillWater1 小时前
阿里Qoder的Quest小试牛刀
后端·aigc
程序猿阿伟1 小时前
《支付回调状态异常的溯源与架构级修复》
后端·架构
uhakadotcom2 小时前
NPM与NPX的区别是什么?
前端·面试·github