Java-Spring Bean 自动启动机制详解 - 从原理到实践
Spring Bean 自动启动机制详解 - 从原理到实践
📚 什么是 Bean 自动启动机制?
简单理解: Spring 在创建 Bean 的时候,可以自动调用一些方法来完成初始化(比如启动服务器)和清理工作(比如关闭服务器)。
类比:
- 就像你买了一台电脑,一开机就自动运行必要的程序(自动启动)
- 关机时自动保存数据并关闭所有程序(自动清理)
🎯 为什么需要自动启动机制?
传统方式的问题
// 传统方式:需要手动调用启动方法
public class MQTTBootStrap {
public void init() {
Server server = new Server();
server.start(); // ❌ 需要手动调用,容易忘记
}
}
问题:
- ❌ 容易忘记调用启动方法
- ❌ 需要手动管理生命周期
- ❌ 代码分散,不集中
Spring 自动启动的优势
@Bean(initMethod = "start", destroyMethod = "stop")
public Server mqttBroker() {
return new Server(); // ✅ Spring 会自动调用 start() 和 stop()
}
优势:
- ✅ 自动调用,不会忘记
- ✅ 代码集中,清晰明了
- ✅ 统一管理生命周期
🔍 核心概念
1. @Bean 注解
@Bean 告诉 Spring:"这个方法会创建一个对象,请帮我管理"
@Configuration
public class MyConfig {
@Bean // 👈 告诉 Spring 这个方法返回的对象需要管理
public Server myServer() {
return new Server();
}
}
2. initMethod(初始化方法)
作用: Bean 创建完成后,自动调用这个方法
@Bean(initMethod = "start") // 👈 Bean 创建后会自动调用 start() 方法
public Server mqttBroker() {
return new Server();
}
执行时机:
创建对象 → 注入依赖 → 调用 initMethod(如 start())
3. destroyMethod(销毁方法)
作用: Spring 容器关闭时,自动调用这个方法
@Bean(initMethod = "start", destroyMethod = "stop") // 👈 关闭时自动调用 stop()
public Server mqttBroker() {
return new Server();
}
执行时机:
应用关闭 → 调用 destroyMethod(如 stop())→ 销毁对象
📖 实战案例:FastBee 项目中的 Bean 启动
让我们通过 FastBee 项目中 MQTT 服务器的启动代码,来理解 Bean 自动启动机制。
完整代码示例
// MQTTBootStrap.java
@Configuration
@ConfigurationProperties(value = "server.broker")
public class MQTTBootStrap {
@Autowired
private MqttServer mqttServer;
private int port;
private int keepAlive;
/**
* 启动 MQTT Broker
*/
@ConditionalOnProperty(value = "server.broker.enabled", havingValue = "true")
@Bean(initMethod = "start", destroyMethod = "stop") // 👈 关键配置
public Server mqttBroker() {
return NettyConfig.custom()
.setIdleStateTime(0, 0, keepAlive)
.setName(ServerType.MQTT.getDes())
.setType(ServerType.MQTT)
.setPort(port)
.setServer(mqttServer)
.build();
}
}
Server 类的实现
// Server.java
public abstract class Server {
protected boolean isRunning;
// 👇 这个方法会被 initMethod 自动调用
public synchronized boolean start() {
if (isRunning) {
log.warn("服务已经运行");
return isRunning;
}
// 启动服务器的逻辑
AbstractBootstrap bootstrap = initialize();
ChannelFuture future = bootstrap.bind(config.port).awaitUninterruptibly();
isRunning = future.isSuccess();
log.info("服务启动成功!端口: {}", config.port);
return isRunning;
}
// 👇 这个方法会被 destroyMethod 自动调用
public synchronized void stop() {
isRunning = false;
bossGroup.shutdownGracefully();
if (workerGroup != null) {
workerGroup.shutdownGracefully();
}
log.warn("服务已经停止!");
}
}
🔄 完整的生命周期流程
Bean 创建和销毁的完整流程
┌─────────────────────────────────────────┐
│ 1. Spring 容器启动 │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ 2. 扫描 @Configuration 类 │
│ 发现 MQTTBootStrap │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ 3. 检查条件(@ConditionalOnProperty) │
│ 如果 server.broker.enabled=true │
│ 继续创建 Bean │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ 4. 调用 @Bean 方法 │
│ Server server = mqttBroker(); │
│ 创建 Server 对象 │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ 5. 注入依赖(如果有) │
│ 给 Server 对象注入需要的依赖 │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ 6. 调用 initMethod │
│ server.start(); 👈 自动调用! │
│ MQTT 服务器启动成功 │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ 7. Bean 可以使用了 │
│ 服务器正在运行 │
└─────────────────────────────────────────┘
↓
... 应用运行中 ...
↓
┌─────────────────────────────────────────┐
│ 8. Spring 容器关闭 │
│ 用户停止应用 │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ 9. 调用 destroyMethod │
│ server.stop(); 👈 自动调用! │
│ MQTT 服务器关闭 │
└─────────────────────────────────────────┘
↓
┌─────────────────────────────────────────┐
│ 10. Bean 销毁 │
│ 清理资源 │
└─────────────────────────────────────────┘
💡 关键特性详解
1. 条件创建:@ConditionalOnProperty
作用: 根据配置决定是否创建 Bean
@ConditionalOnProperty(value = "server.broker.enabled", havingValue = "true")
@Bean(initMethod = "start", destroyMethod = "stop")
public Server mqttBroker() {
// ...
}
含义:
- 只有当配置文件中
server.broker.enabled=true时,才会创建这个 Bean - 如果配置为
false或不存在,这个 Bean 不会被创建
配置文件示例:
# application.yml
server:
broker:
enabled: true # 👈 这个值决定是否创建 Bean
port: 1883
2. 依赖顺序:@DependsOn
作用: 确保某些 Bean 先创建
// SipLayer.java
@Bean("sipFactory")
SipFactory createSipFactory() {
return SipFactory.getInstance();
}
@Bean("sipStack")
@DependsOn("sipFactory") // 👈 确保 sipFactory 先创建
SipStack createSipStack() {
// 这里可以使用 sipFactory
return sipFactory.createSipStack(properties);
}
@Bean("udpSipServer")
@DependsOn("sipStack") // 👈 确保 sipStack 先创建
SipProvider startUdpListener() {
// 这里可以使用 sipStack
return sipStack.createSipProvider(udpListeningPoint);
}
执行顺序:
1. 创建 sipFactory
2. 创建 sipStack(等 sipFactory 创建完成)
3. 创建 udpSipServer(等 sipStack 创建完成)
3. 执行顺序:@Order
作用: 控制配置类的执行顺序
@Order(10) // 👈 数字越小,优先级越高
@Configuration
public class MQTTBootStrap {
// ...
}
📝 常见使用场景
场景1:启动网络服务器
@Bean(initMethod = "start", destroyMethod = "stop")
public Server mqttBroker() {
return new MqttServer();
}
好处: 应用启动时自动启动服务器,关闭时自动停止
场景2:初始化数据库连接池
@Bean(initMethod = "init", destroyMethod = "close")
public DataSource dataSource() {
return new HikariDataSource();
}
场景3:启动定时任务
@Bean(initMethod = "startScheduler", destroyMethod = "shutdown")
public TaskScheduler taskScheduler() {
return new ThreadPoolTaskScheduler();
}
🔧 方法名要求
initMethod 和 destroyMethod 的要求
- 必须是 public 方法
- 可以无参数,或者有参数(Spring 会尝试自动注入)
- 返回类型通常是 void 或 boolean
- 方法名可以是任意的(不一定是
start和stop)
示例:不同的方法名
// 方式1:使用 start/stop
@Bean(initMethod = "start", destroyMethod = "stop")
public Server server1() { return new Server(); }
// 方式2:使用 init/destroy
@Bean(initMethod = "init", destroyMethod = "destroy")
public DataSource dataSource() { return new DataSource(); }
// 方式3:使用自定义方法名
@Bean(initMethod = "initialize", destroyMethod = "cleanup")
public MyService service() { return new MyService(); }
⚠️ 注意事项
1. initMethod 执行失败会怎样?
@Bean(initMethod = "start", destroyMethod = "stop")
public Server mqttBroker() {
return new Server();
}
如果 start() 方法抛出异常:
- ❌ Bean 创建失败
- ❌ 应用可能无法启动
- ✅ 建议在
start()方法中处理异常
2. destroyMethod 执行失败会怎样?
如果 stop() 方法抛出异常:
- ⚠️ 异常会被记录,但不会阻止容器关闭
- ✅ 建议在
stop()方法中捕获异常
3. 不要和 @PostConstruct/@PreDestroy 混淆
// 方式1:使用 initMethod/destroyMethod(推荐用于第三方类)
@Bean(initMethod = "start", destroyMethod = "stop")
public Server server() {
return new Server(); // Server 是第三方类,不能修改
}
// 方式2:使用 @PostConstruct/@PreDestroy(推荐用于自己的类)
@Component
public class MyService {
@PostConstruct // 初始化时调用
public void init() {
// 初始化逻辑
}
@PreDestroy // 销毁时调用
public void cleanup() {
// 清理逻辑
}
}
📊 对比表
| 方式 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|
| initMethod/destroyMethod | 第三方类,不能修改源码 | 不侵入代码 | 只能用于 @Bean 方法 |
| @PostConstruct/@PreDestroy | 自己的类 | 更灵活 | 需要能修改类代码 |
| InitializingBean/DisposableBean | 自己的类 | 接口规范 | 紧耦合 Spring |
🎯 实际案例总结
FastBee 项目中的完整示例
// MQTTBootStrap.java
@Configuration
@ConfigurationProperties(value = "server.broker")
public class MQTTBootStrap {
@Bean(initMethod = "start", destroyMethod = "stop")
@ConditionalOnProperty(value = "server.broker.enabled", havingValue = "true")
public Server mqttBroker() {
// 1. 创建 Server 对象
Server server = NettyConfig.custom()
.setPort(port)
.setServer(mqttServer)
.build();
// 2. Spring 自动调用 server.start()
// 3. MQTT 服务器启动
// 4. 应用关闭时,Spring 自动调用 server.stop()
return server;
}
}
工作流程:
- ✅ Spring 创建
Server对象 - ✅ 自动调用
start()→ MQTT 服务器启动 - ✅ 服务器运行中
- ✅ 应用关闭时自动调用
stop()→ 服务器关闭
💡 最佳实践
✅ 推荐做法
- 网络服务器启动/停止:使用
initMethod/destroyMethod - 资源清理:在
destroyMethod中关闭连接、释放资源 - 条件创建:使用
@ConditionalOnProperty控制是否创建 - 依赖顺序:使用
@DependsOn控制创建顺序
❌ 不推荐做法
- ❌ 在
initMethod中做耗时操作(会阻塞启动) - ❌ 在
destroyMethod中抛出未捕获的异常 - ❌ 忘记处理异常情况
🔍 调试技巧
如何确认 initMethod 被调用了?
@Bean(initMethod = "start", destroyMethod = "stop")
public Server mqttBroker() {
Server server = new Server() {
@Override
public boolean start() {
System.out.println("✅ initMethod 被调用了!"); // 👈 添加日志
return super.start();
}
@Override
public void stop() {
System.out.println("✅ destroyMethod 被调用了!"); // 👈 添加日志
super.stop();
}
};
return server;
}
📚 总结
核心要点
- @Bean(initMethod = "xxx"):Bean 创建后自动调用初始化方法
- @Bean(destroyMethod = "xxx"):容器关闭时自动调用销毁方法
- @DependsOn:控制 Bean 创建顺序
- @ConditionalOnProperty:条件创建 Bean
记忆口诀
Bean 创建自动初始化,容器关闭自动清理
- 创建时 → 调用
initMethod- 关闭时 → 调用
destroyMethod- 有依赖 → 用
@DependsOn- 有条件 → 用
@ConditionalOnProperty
📚 参考代码
本文示例代码来自 FastBee 开源项目:
- MQTTBootStrap:
springboot/fastbee-server/boot-strap/src/main/java/com/fastbee/bootstrap/mqtt/MQTTBootStrap.java - Server:
springboot/fastbee-server/iot-server-core/src/main/java/com/fastbee/server/Server.java - SipLayer:
springboot/fastbee-server/sip-server/src/main/java/com/fastbee/sip/server/SipLayer.java
项目地址:https://github.com/Kerwin1202/fastbee
希望这篇文章能帮你理解 Spring Bean 的自动启动机制! 🚀

浙公网安备 33010602011771号