SpringBoot中bean的生命周期

本文涉及的产品
云原生网关 MSE Higress,422元/月
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
简介: Spring Boot的Bean生命周期涉及实例化、属性注入、初始化和销毁。在实例化后,Spring通过构造函数或Setter注入属性,然后调用初始化方法(@PostConstruct、InitializingBean接口)。Bean在应用中使用后,当容器关闭时,会调用销毁方法(@PreDestroy、DisposableBean接口)。依赖注入、配置管理、组件扩展和切面编程是其常见应用场景。示例代码展示了如何通过实现BeanNameAware、BeanFactoryAware等接口以及使用@PostConstruct注解来控制Bean的初始化。

[toc]

概述

Bean 生命周期管理是 Spring Boot 中的关键功能之一。它负责管理应用程序中的 Java 对象,这些对象被称为 Beans。Spring Boot 通过创建、配置、初始化和销毁这些 Beans 来确保应用程序的正常运行。这个功能的目的是提供一种灵活的方式,使开发人员能够轻松地管理对象的生命周期,从而实现高效的依赖注入和组件化开发。

1、实例化:在 Spring 容器启动时,Spring 会创建配置中定义的所有 Bean。这是通过 Java 类的构造函数或工厂方法来完成的。

2、属性注入:一旦 Bean 被实例化,Spring 会注入所有相关的属性,包括通过构造函数注入或 Setter 方法注入的属性。

3、初始化方法调用:一旦属性被注入,Spring 容器会调用 Bean 的初始化方法。这可以通过@PostConstruct注解、实现InitializingBean接口来完成。初始化过程还提供了一些扩展口:BeanNameAware,BeanFactoryAware,ApplicationContextAware

4、使用 Bean:Bean 现在可以在应用程序中使用,执行其业务逻辑。

5、销毁方法调用:当 Spring 容器关闭时,它会调用 Bean 的销毁方法以释放资源。这可以通过@PreDestroy注解、实现DisposableBean接口来完成。

使用场景

  • 依赖注入:当你需要将一个对象注入到另一个对象中时,Bean 的生命周期管理可以确保被注入的对象已正确初始化。
  • 配置管理:如果你希望根据不同的环境或配置文件来配置 Bean 的属性,Bean 的生命周期管理可以帮助你实现这一目标。
  • 组件扩展:当你需要创建自定义的 Bean,以扩展 Spring Boot 的功能时,Bean 的生命周期管理可以为你提供扩展点。
  • 切面编程:可以在生命周期中预埋代码实现切面编程。例如SpringBoot AOP代理类的实现。

代码演示bean初始化

编写代码演示bean初始化各个节点。

演示代码将创建以下类:

  • TestSupport:一个普通的组件,将作为被观测对象
  • BeanPostProcessorImpl:BeanPostProcessor接口的实现类,用于实现postProcessBeforeInitialization 和postProcessAfterInitialization 并观测TestSupport对象

TestSupport



import com.alibaba.fastjson2.JSON;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;

@Slf4j
@RequiredArgsConstructor
@Component
public class TestSupport implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean {
   
   

    private final ApplicationContext  applicationContext;

    @Override
    public void setBeanName(String s) {
   
   
        log.info("TestSupport-BeanNameAware-setBeanName.param={}", s);
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
   
   
        log.info("TestSupport-BeanFactoryAware-setBeanFactory.param={}", "beanFactory");
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
   
   
        log.info("TestSupport-ApplicationContextAware-setApplicationContext.param={}", JSON.toJSONString(applicationContext.getId()));
    }

    @Override
    public void afterPropertiesSet() throws Exception {
   
   
        log.info("TestSupport-InitializingBean-afterPropertiesSet");
    }

    @PostConstruct
    public void InitSomething() {
   
   
        log.info("通过 @PostConstruct 注解执行自定义初始化逻辑");
    }
}
  • BeanNameAware:通过实现BeanNameAware接口并重写setBeanName方法可以获取到bean的name
  • BeanFactoryAware:通过实现BeanFactoryAware接口并重写setBeanFactory方法可以在bean初始化过程中添加额外的扩展,比如可以通过判断beanFactory.alreadyCreated中是否有某bean而做一些不同的操作
  • ApplicationContextAware:通过实现ApplicationContextAware接口并重写setApplicationContext方法可以在bean初始化过程中添加额外扩展。
  • InitializingBean:通过实现InitializingBean接口并重写afterPropertiesSet 方法可以在bean初始化过程中添加额外扩展。比如将此bean存入map中以备它用
  • @PostConstruct:此外还可以通过在方法上面添加@PostConstruct注解来执行一些自定义的业务代码

BeanPostProcessorImpl



import com.ramble.beanlife.support.TestSupport;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Slf4j
@Component
public class BeanPostProcessorImpl implements BeanPostProcessor {
   
   
    /**
     * bean 加工器之在bean实例化之前得预处理
     * 这个处理类针对所有得bean,所以如果需要对特定得bean做处理需要通过 beanName.equals("testSupport")  或者  bean instanceof TestSupport 来过滤
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
   
   
//        if (beanName.equals("testSupport")) {
   
   
//            log.info("执行  TestSupport 初始化前置方法");
//        }
        if (bean instanceof TestSupport) {
   
   
            log.info("bean 加工器捕捉到  TestSupport ,做初始化前置方法");
        }
        // do something
        return bean;
    }
    /**
     * bean 加工器之在bean实例化之后得预处理
     * @param bean
     * @param beanName
     * @return
     * @throws BeansException
     */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
   
   
//        if (beanName.equals("testSupport")) {
   
   
//            log.info("执行 TestSupport 初始化后置方法");
//        }
        if (bean instanceof TestSupport) {
   
   
            log.info("bean 加工器捕捉到  TestSupport ,做初始化后置方法");
        }
        // do something
        return bean;
    }
}
  • postProcessBeforeInitialization:bean 加工器之在bean初始化完毕之前的预处理
  • postProcessAfterInitialization:bean 加工器之在bean初始化之后的预处理
  • 这个扩展点是针对所有的bean的,所以如果需要观测特定的bean在BeanPostProcessor中的情况,需要通过 bean instanceof 或者 beanName equals 进行判断

log


2024-04-07 15:25:33.488  INFO 51628 --- [           main] com.ramble.beanlife.support.TestSupport  : TestSupport-BeanNameAware-setBeanName.param=testSupport
2024-04-07 15:25:35.271  INFO 51628 --- [           main] com.ramble.beanlife.support.TestSupport  : TestSupport-BeanFactoryAware-setBeanFactory.param=beanFactory
2024-04-07 15:25:35.783  INFO 51628 --- [           main] com.ramble.beanlife.support.TestSupport  : TestSupport-ApplicationContextAware-setApplicationContext.param="bean-life-app"
2024-04-07 15:25:36.198  INFO 51628 --- [           main] c.r.b.processor.BeanPostProcessorImpl    : bean 加工器捕捉到  TestSupport ,做初始化前置方法
2024-04-07 15:25:36.651  INFO 51628 --- [           main] com.ramble.beanlife.support.TestSupport  : 通过 @PostConstruct 注解执行自定义初始化逻辑
2024-04-07 15:25:36.652  INFO 51628 --- [           main] com.ramble.beanlife.support.TestSupport  : TestSupport-InitializingBean-afterPropertiesSet
2024-04-07 15:25:38.453  INFO 51628 --- [           main] c.r.b.processor.BeanPostProcessorImpl    : bean 加工器捕捉到  TestSupport ,做初始化后置方法

通过log打印的顺序可以观测到bean初始化的各个扩展口的执行顺序。

代码

https://gitee.com/naylor_personal/ramble-spring-boot/tree/master/bean-life

目录
相关文章
|
1月前
|
Java
SpringBoot构建Bean(RedisConfig + RestTemplateConfig)
SpringBoot构建Bean(RedisConfig + RestTemplateConfig)
40 2
|
19天前
|
前端开发 Java 数据格式
SpringBoot中定义Bean的几种方式
本文介绍了Spring Boot中定义Bean的多种方式,包括使用@Component、@Bean、@Configuration、@Import等注解及Java配置类。每种方式适用于不同的场景,帮助开发者高效管理和组织应用组件。
|
2月前
|
架构师 Java 开发者
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
在40岁老架构师尼恩的读者交流群中,近期多位读者成功获得了知名互联网企业的面试机会,如得物、阿里、滴滴等。然而,面对“Spring Boot自动装配机制”等核心面试题,部分读者因准备不足而未能顺利通过。为此,尼恩团队将系统化梳理和总结这一主题,帮助大家全面提升技术水平,让面试官“爱到不能自已”。
得物面试:Springboot自动装配机制是什么?如何控制一个bean 是否加载,使用什么注解?
|
2月前
|
Java Spring 容器
Springboot3.2.1搞定了类Service和bean注解同名同类型问题修复
这篇文章讨论了在Spring Boot 3.2.1版本中,同名同类型的bean和@Service注解类之间冲突的问题得到了解决,之前版本中同名bean会相互覆盖,但不会在启动时报错,而在配置文件中设置`spring.main.allow-bean-definition-overriding=true`可以解决这个问题。
100 0
Springboot3.2.1搞定了类Service和bean注解同名同类型问题修复
|
3月前
|
Java Spring
springboot 集成 swagger 2.x 和 3.0 以及 Failed to start bean ‘documentationPluginsBootstrapper‘问题的解决
本文介绍了如何在Spring Boot项目中集成Swagger 2.x和3.0版本,并提供了解决Swagger在Spring Boot中启动失败问题“Failed to start bean ‘documentationPluginsBootstrapper’; nested exception is java.lang.NullPointerEx”的方法,包括配置yml文件和Spring Boot版本的降级。
springboot 集成 swagger 2.x 和 3.0 以及 Failed to start bean ‘documentationPluginsBootstrapper‘问题的解决
|
2月前
|
Java Shell C++
Springboot加载注入bean的方式
本文详细介绍了Spring Boot中Bean的装配方法。首先讲解了使用@Component、@Service、@Controller、@Repository等注解声明Bean的方式,并解释了这些注解之间的关系及各自适用的层次。接着介绍了通过@Configuration和@Bean注解定义Bean的方法,展示了其灵活性和定制能力。最后讨论了@Component与@Bean的区别,并提供了在Spring Boot应用中装配依赖包中Bean的三种方法:使用@ComponentScan注解扫描指定包、使用@Import注解导入特定Bean以及在spring.factories文件中配置Bean。
|
5月前
|
Java Spring 容器
Spring Boot 启动源码解析结合Spring Bean生命周期分析
Spring Boot 启动源码解析结合Spring Bean生命周期分析
111 11
|
5月前
|
消息中间件 Java Kafka
Spring boot 自定义kafkaTemplate的bean实例进行生产消息和发送消息
Spring boot 自定义kafkaTemplate的bean实例进行生产消息和发送消息
208 5
|
4月前
|
Java Spring 容器
Java SpringBoot 中,动态执行 bean 对象中的方法
Java SpringBoot 中,动态执行 bean 对象中的方法
42 0
|
4月前
|
Java Spring
Java SpringBoot Bean InitializingBean 项目初始化
Java SpringBoot Bean InitializingBean 项目初始化
62 0