当前位置: 首页 > news >正文

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 {@Autowiredprivate 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  # 👈 这个值决定是否创建 Beanport: 1883

2. 依赖顺序:@DependsOn

作用: 确保某些 Bean 先创建

// SipLayer.java
@Bean("sipFactory")
SipFactory createSipFactory() {return SipFactory.getInstance();
}@Bean("sipStack")
@DependsOn("sipFactory")  // 👈 确保 sipFactory 先创建
SipStack createSipStack() {// 这里可以使用 sipFactoryreturn sipFactory.createSipStack(properties);
}@Bean("udpSipServer")
@DependsOn("sipStack")  // 👈 确保 sipStack 先创建
SipProvider startUdpListener() {// 这里可以使用 sipStackreturn 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 的要求

  1. 必须是 public 方法
  2. 可以无参数,或者有参数(Spring 会尝试自动注入)
  3. 返回类型通常是 void 或 boolean
  4. 方法名可以是任意的(不一定是 startstop

示例:不同的方法名

// 方式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;}
}

工作流程:

  1. ✅ Spring 创建 Server 对象
  2. ✅ 自动调用 start() → MQTT 服务器启动
  3. ✅ 服务器运行中
  4. ✅ 应用关闭时自动调用 stop() → 服务器关闭

💡 最佳实践

✅ 推荐做法

  1. 网络服务器启动/停止:使用 initMethod/destroyMethod
  2. 资源清理:在 destroyMethod 中关闭连接、释放资源
  3. 条件创建:使用 @ConditionalOnProperty 控制是否创建
  4. 依赖顺序:使用 @DependsOn 控制创建顺序

❌ 不推荐做法

  1. ❌ 在 initMethod 中做耗时操作(会阻塞启动)
  2. ❌ 在 destroyMethod 中抛出未捕获的异常
  3. ❌ 忘记处理异常情况

🔍 调试技巧

如何确认 initMethod 被调用了?

@Bean(initMethod = "start", destroyMethod = "stop")
public Server mqttBroker() {Server server = new Server() {@Overridepublic boolean start() {System.out.println("✅ initMethod 被调用了!");  // 👈 添加日志return super.start();}@Overridepublic void stop() {System.out.println("✅ destroyMethod 被调用了!");  // 👈 添加日志super.stop();}};return server;
}

📚 总结

核心要点

  1. @Bean(initMethod = "xxx"):Bean 创建后自动调用初始化方法
  2. @Bean(destroyMethod = "xxx"):容器关闭时自动调用销毁方法
  3. @DependsOn:控制 Bean 创建顺序
  4. @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 的自动启动机制! 🚀

http://www.jsqmd.com/news/140203/

相关文章:

  • 数字
  • 12月24日日记
  • 昇腾 NPU 环境下 GPT-2 模型本地部署全指南(含踩坑排错)
  • 《具身智能》读书笔记
  • PhysicReviewsNotes
  • 2025最新!专科生必看9大AI论文平台测评与推荐
  • 150_尚硅谷_数组应用实例(2)
  • 大一职业规划
  • 怎么制作一个可执行的测试计划
  • 江苏诚信的港澳台联考机构哪家专业
  • 告别论文恐惧症!2025年7款最强AI写作神器,一键生成、轻松降重、查重无忧!
  • ios跟安卓出现崩溃怎么获取日志
  • linux 中 sed命令跳过指定行
  • 汉字
  • 业绩很牛的销售,都在练基本功!
  • CF803C Maximal GCD做题笔记
  • 观bilibi《超强动画,一步一步一步深入浅出解释Transformer原理!》有感
  • 性能测试中关于硬件环境的测试
  • Java-Spring 依赖注入详解--多个类实现与选择 - 若
  • 一键激活 Windows 与 Office 的轻量绿色工具!
  • centos7配置yum软件源
  • 2025年西安电子科技大学计算机考研复试机试真题(附 AC 代码 + 解题思路)
  • 学长亲荐8个AI论文工具,研究生轻松搞定开题报告!
  • 2025最新!9款AI论文软件测评:本科生写论文痛点全解析
  • ubuntu虚拟机mysql数据库忘记密码
  • Selenium + 超级鹰实现猎聘网滑块验证码自动登录
  • 2025年北京邮电大学计算机考研复试机试真题(附 AC 代码 + 解题思路)
  • 「AI元人文构想」对话全记录:从困境、构想到系统自洽的七十日
  • 链表|160.相交链表234.回文指针141环形链表
  • Linux中级の自动运维工具Ansible基础