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**标准化更加规范。

相关推荐
大数据编程之光15 分钟前
Flink Standalone集群模式安装部署全攻略
java·大数据·开发语言·面试·flink
爪哇学长28 分钟前
双指针算法详解:原理、应用场景及代码示例
java·数据结构·算法
ExiFengs32 分钟前
实际项目Java1.8流处理, Optional常见用法
java·开发语言·spring
paj12345678934 分钟前
JDK1.8新增特性
java·开发语言
捂月40 分钟前
Spring Boot 深度解析:快速构建高效、现代化的 Web 应用程序
前端·spring boot·后端
繁依Fanyi1 小时前
简易安卓句分器实现
java·服务器·开发语言·算法·eclipse
慧都小妮子1 小时前
Spire.PDF for .NET【页面设置】演示:打开 PDF 时自动显示书签或缩略图
java·pdf·.net
m51271 小时前
LinuxC语言
java·服务器·前端
IU宝1 小时前
C/C++内存管理
java·c语言·c++
瓜牛_gn1 小时前
依赖注入注解
java·后端·spring