Spring bean的生命周期

一、Spring框架中Bean的生命周期

可以分为以下几个主要阶段:

1. 实例化: 当Spring容器启动并读取配置元数据(如XML配置、注解或Java配置类)时,它会创建Bean定义的实例。对于 singleton scope 的Bean,这会在容器启动时发生一次;而对于 prototype scope,每次请求Bean时都会创建新实例。

2. 属性填充: Spring通过反射调用Bean实例的setter方法或使用构造器注入来设置依赖项。这包括注入其他Bean、基本类型的值或集合类型的属性。

3. Aware接口注入: 如果Bean实现了Spring的Aware接口(如BeanNameAware、ApplicationContextAware等),Spring会调用相应的回调方法,允许Bean知道它们所在的容器或它们的Bean名称等信息。

4. 初始化前处理: 如果Bean定义中指定了InitializingBean接口,Spring会调用其afterPropertiesSet()方法。这是在自定义初始化回调之前执行的,可以用来执行一些初始化工作。

5. 自定义初始化方法: 开发者可以通过@PostConstruct注解或在Spring配置中指定init-method属性来定义自定义的初始化方法。Spring会在所有必需的属性设置之后调用这些方法。

6. Bean准备就绪: 至此,Bean已经完全初始化并准备好被应用程序使用。对于 singleton Beans,它们将被放入Spring容器的单例缓存中。

7. 使用Bean: 应用程序可以通过依赖查找或自动装配来使用Bean。

8. 销毁前处理: 如果Bean实现了DisposableBean接口,当容器关闭时,Spring会调用其destroy()方法。此外,也可以使用@PreDestroy注解或在配置中指定destroy-method来执行自定义的销毁逻辑。

9. 销毁: 对于非 singleton scope 的Bean(如 prototype),Spring容器不负责销毁,而是由Java垃圾收集器来处理。对于 singleton scope 的Bean,当Spring容器关闭时,会执行销毁方法,释放资源。

二、Spring Bean生命周期的案例,使用Java配置方式来展示各个阶段

1. 定义一个简单的Bean类,包含初始化和销毁方法:

java 复制代码
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

public class ExampleBean {

  public ExampleBean() {
    System.out.println("2. Bean实例化 - 调用构造函数");
  }

  // 使用@PostConstruct注解标记初始化方法
  @PostConstruct
  public void init() {
    System.out.println("3. 初始化 - 调用@PostConstruct注解的方法");
  }

  // 使用@PreDestroy注解标记销毁方法
  @PreDestroy
  public void cleanup() {
    System.out.println("9. 销毁 - 调用@PreDestroy注解的方法");
  }

  public void sayHello() {
    System.out.println("bean内部方法:Hello from ExampleBean!");
  }

  // 自定义初始化方法,现在看来@PostConstruct注解已经可以满足需求了,但是还是留着自定义初始化方法的例子
  private void customInit() {
    System.out.println("customInit - 调用customInit");
  }
}

2. 创建Spring的Java配置类,配置ExampleBean

java 复制代码
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

  // 定义Bean
  @Bean(initMethod = "customInit", destroyMethod = "cleanup")
  public ExampleBean exampleBean() {
    System.out.println("1. Bean实例化 - Spring调用配置方法创建Bean");
    return new ExampleBean();
  }
}

尽管我们已经在ExampleBean中使用了@PostConstruct和@PreDestroy注解,这里为了演示配置方式,仍然在@Bean注解中指定了初始化和销毁方法。实际上,直接使用注解通常是首选。

3. 编写一个主类来启动Spring容器并使用Bean:

java 复制代码
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainApp {

    public static void main(String[] args) {
        System.out.println("0. Spring容器初始化开始");

        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        System.out.println("4. Bean已准备就绪,可以使用");

        ExampleBean bean = context.getBean(ExampleBean.class);
        bean.sayHello();

        System.out.println("8. Spring容器关闭开始");

        ((AnnotationConfigApplicationContext) context).close();

        System.out.println("10. Spring容器已关闭");
    }
}

当运行MainApp时,控制台输出将按照以下顺序显示:

  1. Spring容器初始化开始

  2. Bean实例化 - Spring调用配置方法创建Bean

  3. Bean实例化 - 调用构造函数

  4. 初始化 - 调用@PostConstruct注解的方法

customInit - 调用customInit

  1. Bean已准备就绪,可以使用

bean内部方法:Hello from ExampleBean!

  1. Spring容器关闭开始

  2. 销毁 - 调用@PreDestroy注解的方法

  3. Spring容器已关闭

注:@PostConstruct和initMethod

@PostConstruct
来源 : @PostConstruct是JSR-250规范的一部分,它是Java EE提供的标准注解,用于在依赖关系设置之后但在Bean被任何其他Bean使用之前调用初始化方法。
使用场景 : 当你需要一个跨框架的标准化初始化注解时,或者你的应用不仅仅局限于Spring框架,那么使用@PostConstruct更为合适。

优点: 标准化,不绑定到特定框架,提高了代码的可移植性。

init-method
来源 : init-method是Spring框架特有的配置方式,通过在Spring的XML配置文件或Java配置类中的@Bean注解里指定初始化方法名称。
使用场景: 如果你的应用完全基于Spring框架,并且希望利用Spring提供的更多特性或与Spring的其他配置风格保持一致,那么使用init-method可能更合适。

@PostConstructinitMethod 都可以用来指定Bean的初始化方法,通过上面的案例可知, @PostConstruct 注解更加标准化,最先进行初始化。而 initMethod 更像是一个初始化后,自定义的方法,两者往往可以互换使用,也可以共存使用,但**@PostConstruct**标准化更加规范。

相关推荐
Query*7 分钟前
杭州2024.08 Java开发岗面试题分类整理【附面试技巧】
java·开发语言·面试
WZTTMoon15 分钟前
Spring Boot 4.0 迁移核心注意点总结
java·spring boot·后端
寻kiki15 分钟前
scala 函数类?
后端
疯狂的程序猴26 分钟前
iOS App 混淆的真实世界指南,从构建到成品 IPA 的安全链路重塑
后端
旷野说33 分钟前
为什么 MyBatis 原生二级缓存“难以修复”?
java·java-ee·mybatis
8***235536 分钟前
【wiki知识库】07.用户管理后端SpringBoot部分
java
bcbnb37 分钟前
iOS 性能测试的工程化方法,构建从底层诊断到真机监控的多工具测试体系
后端
开心就好202541 分钟前
iOS 上架 TestFlight 的真实流程复盘 从构建、上传到审核的团队协作方式
后端
小周在成长1 小时前
Java 泛型支持的类型
后端
aiopencode1 小时前
Charles 抓不到包怎么办?HTTPS 抓包失败、TCP 数据流异常与底层补抓方案全解析
后端