Spring Bean的生命周期

Spring Bean的生命周期,不仅涵盖每个阶段的细节,还包括Spring内部如何处理这些阶段,以及如何利用这些阶段来满足特定的需求。

1. Spring容器的启动

在Spring容器启动时,它会读取配置元数据(XML配置文件、Java配置类或注解),并开始实例化和初始化Bean。Spring容器的启动通常从调用ApplicationContext的实现类(如ClassPathXmlApplicationContext或AnnotationConfigApplicationContext)的构造函数开始。在启动过程中,容器会执行一系列初始化操作,其中包括加载Bean定义、解析依赖关系以及初始化Bean。

2. 实例化 (Instantiation)

当Spring容器需要创建一个Bean时,它首先会根据配置信息调用相应的构造函数来实例化Bean。这个过程是通过BeanFactory来完成的。如果Bean定义中指定了工厂方法,那么Spring会调用该方法来创建Bean。

  • 无参构造器:这是最常见的实例化方式。
  • 工厂方法 :可以通过factory-bean和factory-method属性指定工厂Bean和工厂方法。
  • 静态工厂方法 :如果指定了class属性为静态工厂类,并且factory-method属性为静态方法,那么Spring会调用该静态方法来创建Bean。

3. 属性填充 (Populate Bean Properties)

一旦Bean被实例化,Spring就会开始填充Bean的属性。这个过程包括依赖注入和其他属性设置。

  • 依赖注入 :Spring根据Bean定义中的<property>标签或@Autowired注解来注入依赖。
  • 自动装配 :Spring支持通过autowire属性来自动装配依赖,或者使用@Autowired注解来实现自动装配。

4. 设置Bean名称 (Bean Name Aware)

如果Bean实现了BeanNameAware接口,Spring会在Bean的属性设置之后,但在初始化之前调用setBeanName方法,将Bean的名称传递给Bean。

复制代码
public class MyBean implements BeanNameAware {
    private String beanName;

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("BeanNameAware: Bean name is " + name);
    }
}

5. 设置Bean工厂 (Bean Factory Aware)

如果Bean实现了BeanFactoryAware接口,Spring会在属性设置之后,但在初始化之前调用setBeanFactory方法,将BeanFactory传递给Bean。

复制代码
public class MyBean implements BeanFactoryAware {
    private BeanFactory beanFactory;

    @Override
    public void setBeanFactory(BeanFactory factory) throws BeansException {
        this.beanFactory = factory;
        System.out.println("BeanFactoryAware: BeanFactory is set");
    }
}

6. 设置应用上下文 (Application Context Aware)

如果Bean实现了ApplicationContextAware接口,Spring会在属性设置之后,但在初始化之前调用setApplicationContext方法,将ApplicationContext传递给Bean。

复制代码
public class MyBean implements ApplicationContextAware {
    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext context) throws BeansException {
        this.applicationContext = context;
        System.out.println("ApplicationContextAware: ApplicationContext is set");
    }
}

7. 预初始化处理 (Pre-Initialization Processing)

在Bean初始化之前,Spring会调用所有注册的BeanPostProcessor的postProcessBeforeInitialization方法。BeanPostProcessor接口允许我们在Bean初始化前后插入自定义逻辑。

复制代码
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor: Before initialization of " + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("BeanPostProcessor: After initialization of " + beanName);
        return bean;
    }
}

8. 初始化 (Initialization)

  • InitializingBean接口 :如果Bean实现了InitializingBean接口,Spring会在属性设置之后调用afterPropertiesSet方法。

    public class MyBean implements InitializingBean {
    @Override
    public void afterPropertiesSet() throws Exception {
    System.out.println("InitializingBean: afterPropertiesSet method called");
    }
    }

  • init-method :如果在Bean定义中指定了init-method属性,Spring会调用该方法。

  • @PostConstruct注解 :如果Bean的方法上标注了@PostConstruct,Spring会在依赖注入完成后调用该方法。

    public class MyBean {
    @PostConstruct
    public void init() {
    System.out.println("@PostConstruct: Initialization method called");
    }
    }

9. 后初始化处理 (Post-Initialization Processing)

在Bean初始化之后,Spring会再次调用所有注册的BeanPostProcessor的postProcessAfterInitialization方法。

10. 使用 (Usage)

此时,Bean已经完全初始化,可以被应用程序使用。Spring容器会将Bean存储在单例池中(如果是单例作用域),以便后续请求时可以直接获取。

11. 销毁 (Destruction)

  • DisposableBean接口 :如果Bean实现了DisposableBean接口,Spring会在容器关闭时调用destroy方法。

    public class MyBean implements DisposableBean {
    @Override
    public void destroy() throws Exception {
    System.out.println("DisposableBean: destroy method called");
    }
    }

  • destroy-method :如果在Bean定义中指定了destroy-method属性,Spring会在容器关闭时调用该方法。

  • @PreDestroy注解 :如果Bean的方法上标注了@PreDestroy,Spring会在销毁Bean之前调用该方法。

    public class MyBean {
    @PreDestroy
    public void cleanup() {
    System.out.println("@PreDestroy: Cleanup method called");
    }
    }

示例代码

下面是一个完整的示例,展示了如何在一个Bean中实现和使用这些接口和注解。

复制代码
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
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.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Component;

@Component
@Lazy
public class MyBean implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {

    private String beanName;
    private BeanFactory beanFactory;
    private ApplicationContext applicationContext;

    // 构造函数
    public MyBean() {
        System.out.println("MyBean instance created.");
    }

    // BeanNameAware接口方法
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
        System.out.println("BeanNameAware: Bean name is " + name);
    }

    // BeanFactoryAware接口方法
    @Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
        System.out.println("BeanFactoryAware: BeanFactory is set");
    }

    // ApplicationContextAware接口方法
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
        System.out.println("ApplicationContextAware: ApplicationContext is set");
    }

    // InitializingBean接口方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("InitializingBean: afterPropertiesSet method called");
    }

    // @PostConstruct注解的方法
    @PostConstruct
    public void init() {
        System.out.println("@PostConstruct: Initialization method called");
    }

    // @PreDestroy注解的方法
    @PreDestroy
    public void cleanup() {
        System.out.println("@PreDestroy: Cleanup method called");
    }

    // DisposableBean接口方法
    @Override
    public void destroy() throws Exception {
        System.out.println("DisposableBean: destroy method called");
    }
}

总结

Spring Bean的生命周期是一个高度灵活和可扩展的过程。通过实现不同的生命周期回调接口和使用注解,我们可以控制Bean在各个阶段的行为。这使得我们能够有效地管理Bean的初始化和清理,尤其是在处理外部资源(如数据库连接、网络连接等)时尤为重要。

此外,Spring还提供了许多其他的扩展点,如BeanPostProcessor、BeanFactoryPostProcessor等,这些都可以用来在Bean的生命周期中插入自定义逻辑。

相关推荐
十年Java程序媛11 分钟前
Java 接口和抽象类对比|Java8 新特性,抛弃老旧八股,正确选型
java·spring boot·后端
caoerzhong13 分钟前
JeeWMS 开源 WMS 部署避坑指南:Java 仓库管理系统的环境基线、四类根因与可复现交付
java·开发语言·开源
用户37215742613513 分钟前
Java 合并 PDF 文件:完整合并、指定页面合并与流合并
java
for_ever_love__1 小时前
MySQL 全文索引实战:FULLTEXT、ngram 中文分词与 MATCH AGAINST 到底该怎么用
java·python·mysql·全文检索·分词·索引·ngram
java资料站1 小时前
五、Spring AI Alibaba · Memory · Saver(短期会话)
java·spring·microsoft
夜之眷属2 小时前
Core dump 崩溃排查:JVM 宕机后,那份 core 文件怎么用 gdb 还原现场
java·运维·服务器·jvm
波加曼大王2 小时前
# vLLM不要迷信PagedAttention神话,聊聊线上藏着的内部碎片陷阱
java·架构
SL_staff2 小时前
目标健康度自检清单:开发者视角下的目标-计划-任务链路断点诊断
java·开源·github
for_ever_love__2 小时前
MySQL 高频面试题 30 问:索引、事务、锁、日志、主从与分库分表(MySQL 8.0 版)
java·数据库·spring boot·mysql·spring cloud·面试·总结
神仙别闹2 小时前
基于C++实现的贪吃蛇游戏平台
java·c++·游戏