下面我将通过一个具体的 Java 示例,详细说明 Spring 中 Bean 的生命周期各个阶段,并为每一步添加注释解释其作用。
Spring 容器根据配置信息创建一个 Bean 的实例(调用构造函数)。
public class MyBean {
public MyBean() {
System.out.println("1. Bean 被实例化(构造方法调用)");
}
}
✅ 做了什么?
JVM 为 MyBean
对象分配内存空间,并调用无参构造函数初始化对象。
如果 Bean 有依赖项或需要注入的值,Spring 会进行依赖注入。
public class MyBean {
private String message;
public void setMessage(String message) {
this.message = message;
System.out.println("2. 属性注入:setMessage(" + message + ")");
}
// ...
}
✅ 做了什么?
Spring 调用了 setMessage("Hello")
方法,把配置文件中定义的值注入到 Bean 中。
这些接口允许 Bean 获取容器中的关键组件,如名称、工厂、上下文等。
@Component
public class MyBean implements BeanNameAware, ApplicationContextAware {
@Override
public void setBeanName(String name) {
System.out.println("3.1.1 setBeanName: Bean 名称是 " + name);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
System.out.println("3.1.2 setApplicationContext: 应用上下文已设置");
}
// ...
}
✅ 做了什么?
setBeanName()
让 Bean 知道自己在容器中的名字。setApplicationContext()
提供对整个 Spring 容器的访问。BeanPostProcessor
初始化前置方法如果有自定义的 BeanPostProcessor
,它会在初始化前处理这个 Bean。
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (bean instanceof MyBean) {
System.out.println("3.2 postProcessBeforeInitialization: Bean 初始化前处理");
}
return bean;
}
}
✅ 做了什么?
这是插件机制的一部分,可以在所有 Bean 初始化之前做一些通用处理,比如日志记录、代理增强等。
@PostConstruct
初始化方法(依赖注入后执行)该注解用于标记在依赖注入完成后要执行的初始化逻辑。
@PostConstruct
public void postConstruct() {
System.out.println("3.3 @PostConstruct: 初始化方法,在依赖注入之后执行");
}
✅ 做了什么?
这是一个非常常用的注解,适合做一些资源加载、连接池初始化等工作。
init-method
方法(如果有指定)你也可以在 XML 或 @Bean
注解中指定一个初始化方法。
public class MyBean {
public void customInitMethod() {
System.out.println("3.4 自定义 init-method: 自定义初始化逻辑");
}
}
XML 配置方式:
<bean id="myBean" class="com.example.MyBean" init-method="customInitMethod"/>
或者使用 @Bean
:
@Bean(initMethod = "customInitMethod")
public MyBean myBean() {
return new MyBean();
}
✅ 做了什么?
提供了一种与 Spring 解耦的方式来执行初始化逻辑。
BeanPostProcessor
初始化后置方法和前置类似,但是在初始化之后执行。
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof MyBean) {
System.out.println("3.5 postProcessAfterInitialization: Bean 初始化后处理");
}
return bean;
}
✅ 做了什么?
可用于 AOP 代理生成、日志增强等操作。
此时 Bean 已经完全准备好,可以被正常使用。
@Service
public class MyService {
@Autowired
private MyBean myBean;
public void useBean() {
System.out.println("4. 使用 Bean");
}
}
✅ 做了什么?
Bean 可以参与业务逻辑,被其他组件调用。
当 Spring 容器关闭时,会执行销毁逻辑。
@PreDestroy
注解方法@PreDestroy
public void preDestroy() {
System.out.println("5.1 @PreDestroy: 在销毁前执行");
}
✅ 做了什么?
通常用来释放资源,如关闭数据库连接、线程池等。
DisposableBean
接口public class MyBean implements DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("5.2 DisposableBean.destroy(): Spring 标准销毁方法");
}
}
✅ 做了什么?
Spring 提供的标准销毁回调接口。
destroy-method
类似于 init-method
,你可以指定一个销毁方法。
public class MyBean {
public void customDestroyMethod() {
System.out.println("5.3 自定义 destroy-method: 自定义销毁逻辑");
}
}
XML 配置方式:
<bean id="myBean" class="com.example.MyBean" destroy-method="customDestroyMethod"/>
或者使用 @Bean
:
@Bean(destroyMethod = "customDestroyMethod")
public MyBean myBean() {
return new MyBean();
}
✅ 做了什么?
提供了灵活的销毁逻辑配置方式。
如果你运行上面的代码,控制台输出大概是这样的顺序:
1. Bean 被实例化(构造方法调用)
2. 属性注入:setMessage(Hello)
3.1.1 setBeanName: Bean 名称是 myBean
3.1.2 setApplicationContext: 应用上下文已设置
3.2 postProcessBeforeInitialization: Bean 初始化前处理
3.3 @PostConstruct: 初始化方法,在依赖注入之后执行
3.4 自定义 init-method: 自定义初始化逻辑
3.5 postProcessAfterInitialization: Bean 初始化后处理
4. 使用 Bean
...
5.1 @PreDestroy: 在销毁前执行
5.2 DisposableBean.destroy(): Spring 标准销毁方法
5.3 自定义 destroy-method: 自定义销毁逻辑
在 Spring Boot 中,如果你想让 @PreDestroy
和 destroy-method
正常执行,必须确保应用是正常关闭的。例如:
@SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(Application.class, args);
// 模拟运行一段时间
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 正常关闭容器
context.close();
}
}
否则,直接结束进程(如 Ctrl+C),可能会跳过销毁阶段。