程序启动时调用事件的顺序

执行顺序:

applicationComplete->creationComplete->initialize


测试代码:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:controls="com.fxcomponents.controls.*" 
backgroundColor="#444444" themeColor="#628CAF" backgroundGradientAlphas="{[0, 0]}" initialize="init1()"
applicationComplete="init3()" creationComplete="init2()">
<mx:Script>
   <![CDATA[ 
   import mx.controls.Alert;   
  
   private function init1(): void
    {
    Alert.show("init1");
    }
   
    private function init2(): void
    {
    Alert.show("init2");
    }
    public function init3(): void
    {
    Alert.show("init3");
    }

   ]]>
</mx:Script>
</mx:Application>


<think> 我们正在讨论的是Spring Boot程序启动时调用注解的方法。根据引用,我们知道Spring Boot在启动时可以通过多种方式执行代码。结合用户的查询和引用内容,我们将重点放在在程序启动时通过注解调用方法上。 引用[4]提到了使用`@EventListener`注解监听`ApplicationStartedEvent`事件,在应用启动后执行代码。此外,引用[2]中提到了`@PostConstruct`注解,虽然它不是在Spring Boot启动事件中,但它在bean初始化时执行,通常也可以用于启动时执行代码(但注意,这发生在bean初始化阶段,并非完全等同于应用启动完成)。 另外,引用[4]还提到了实现`ApplicationRunner`接口(使用`@Component`注解)或`CommandLineRunner`接口,这两种方式也是在应用启动完成后执行代码的常用方法,但并非通过注解直接标记方法,而是通过实现接口并重写`run`方法。 因此,我们主要关注以下几种在Spring Boot启动时通过注解调用方法的方式: 1. **使用`@EventListener`监听Spring Boot事件**:监听`ApplicationStartedEvent`(应用启动完成)等事件。 2. **使用`@PostConstruct`注解**:在Bean初始化时执行(注意:此时应用上下文可能尚未完全就绪,例如数据库连接还未建立等)。 3. **使用`@Bean`结合初始化方法**:在配置类中定义Bean时,指定初始化方法(例如`@Bean(initMethod = "init")`)。 4. **使用`@Scheduled`注解**:结合`@EnableScheduling`,可以在应用启动后定时执行,但需要配置`initialDelay`来指定启动后立即执行。 但是,用户问题明确要求“程序启动时调用注解的方法”,所以我们重点放在注解方式上。 下面详细说明: ### 1. 使用`@EventListener`监听启动事件 Spring Boot在启动过程中会发布一系列事件,我们可以通过监听这些事件来执行代码。常用的事件有: - `ApplicationStartedEvent`:应用启动完成时触发,此时Spring容器已经初始化完毕,但此时命令行参数和ApplicationRunner等尚未运行。 - `ApplicationReadyEvent`:应用准备就绪时触发,此时所有Bean已初始化,ApplicationRunner等也已运行。 示例: ```java import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class StartupEventListener { @EventListener(ApplicationReadyEvent.class) public void onApplicationReady() { // 应用已就绪,可以在这里执行启动代码 System.out.println("Application is ready!"); } } ``` ### 2. 使用`@PostConstruct`注解 该注解是JSR-250规范的一部分,用于标记在Bean初始化完成后执行的方法。注意:该方法会在Bean的依赖注入完成后执行,但此时整个应用上下文可能还未完全就绪(比如其他Bean可能还未初始化完成)。 示例: ```java import javax.annotation.PostConstruct; import org.springframework.stereotype.Component; @Component public class PostConstructExample { @PostConstruct public void init() { System.out.println("Bean初始化完成,执行@PostConstruct方法"); } } ``` ### 3. 使用`@Bean`的初始化方法 在配置类中定义Bean时,可以指定初始化方法(通过`initMethod`属性)。该方法会在Bean初始化时调用。 示例: ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class AppConfig { @Bean(initMethod = "init") public MyBean myBean() { return new MyBean(); } public static class MyBean { public void init() { System.out.println("Bean通过initMethod初始化"); } } } ``` ### 4. 使用`@Scheduled`注解实现启动后执行 如果结合`@EnableScheduling`,我们可以设置一个定时任务,在启动后立即执行一次(通过设置`initialDelay`为0,并设置`fixedDelay`为负数表示只执行一次)。 示例: ```java import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component @EnableScheduling // 通常放在主配置类上,这里放在组件上也可以但推荐放在配置类 public class StartupScheduler { @Scheduled(initialDelay = 0, fixedDelay = -1) public void onStartup() { System.out.println("应用启动后立即执行"); } } ``` ### 5. 使用`ApplicationRunner`或`CommandLineRunner`接口 虽然这两个接口不是直接通过注解调用方法,但它们通常与`@Component`一起使用,在应用启动完成后执行。它们是在`ApplicationReadyEvent`之前执行的(在`ApplicationStartedEvent`之后)。 示例: ```java import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; @Component public class MyApplicationRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) throws Exception { System.out.println("ApplicationRunner执行启动代码"); } } ``` ### 总结 - **推荐使用`@EventListener(ApplicationReadyEvent.class)`**:确保应用已完全就绪,适合大多数启动任务[^4]。 - **避免在`@PostConstruct`中执行耗时操作或依赖其他未初始化的Bean**:因为此时部分Bean可能尚未初始化完成。 - **注意执行顺序**:`ApplicationRunner`和`CommandLineRunner`的执行介于`ApplicationStartedEvent`和`ApplicationReadyEvent`之间。 如果需要在Spring Boot启动时执行代码,根据具体需求选择合适的方法。对于需要在应用完全就绪后执行的代码,优先选择监听`ApplicationReadyEvent`事件。 §§相关问题§§ 1. Spring Boot启动事件有哪些?它们的触发顺序是怎样的? 2. 如何在Spring Boot中安全地执行异步启动任务? 3. 使用`@PostConstruct`和`@PreDestroy`注解有哪些注意事项? 4. 如何在Spring Boot启动时执行数据库初始化脚本? 5. 如何控制多个`ApplicationRunner`或`CommandLineRunner`的执行顺序? [^1]: 引用[1]提到注解在Spring Boot中用于配置和管理项目。 [^2]: 引用[2]列出Spring Boot常用注解,包括配置、Controller、注入等。 [^4]: 引用[4]介绍了使用`@EventListener`监听启动事件以及实现`ApplicationRunner`接口。 </think> ### Spring Boot 程序启动时调用注解的方法详解 在 Spring Boot 中,有以下五种常用方式可以在程序启动时通过注解调用方法: #### 1. **`@EventListener` 监听启动事件** [^4] ```java import org.springframework.boot.context.event.ApplicationStartedEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component; @Component public class StartupListener { @EventListener(ApplicationStartedEvent.class) public void onStartup() { System.out.println("应用已启动完成!资源初始化中..."); // 这里执行初始化逻辑(如加载配置、预加载缓存) } } ``` - **触发时机**:应用上下文完全初始化后 - **优点**:精确控制执行阶段 - **典型场景**:数据库连接池初始化,第三方服务预热 #### 2. **`@PostConstruct` 初始化方法** [^2] ```java import javax.annotation.PostConstruct; import org.springframework.stereotype.Service; @Service public class CacheService { @PostConstruct public void initCache() { System.out.println("Bean初始化时执行缓存预热"); // 初始化本地缓存 } } ``` - **触发时机**:Bean 依赖注入完成后 - **注意点**:需确保依赖的 Bean 已就绪 - **典型场景**:内存缓存初始化,静态资源配置 #### 3. **`ApplicationRunner` 接口** [^4] ```java import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; @Component public class AppRunner implements ApplicationRunner { @Override public void run(ApplicationArguments args) { System.out.println("启动参数解析完成!"+ args.getOptionNames()); // 执行启动参数相关逻辑 } } ``` - **触发时机**:在 `ApplicationStartedEvent` 之后,`ApplicationReadyEvent` 之前 - **优势**:可访问启动参数 `ApplicationArguments` #### 4. **`CommandLineRunner` 接口** [^4] ```java import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component; @Component public class CliRunner implements CommandLineRunner { @Override public void run(String... args) { System.out.println("命令行参数处理:" + Arrays.toString(args)); // 处理命令行参数 } } ``` - **触发时机**:与 `ApplicationRunner` 类似 - **区别**:直接接收原始字符串参数(而非结构化对象) #### 5. **`@Scheduled` 定时任务**(立即执行)[^2] ```java import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @Component public class ImmediateTask { @Scheduled(fixedDelay = Long.MAX_VALUE, initialDelay = 0) public void startupTask() { System.out.println("启动后立即执行一次的任务"); // 执行后不再重复 } } ``` - **关键参数**:`initialDelay=0` 表示立即启动 - **注意**:需在主类添加 `@EnableScheduling` ### 执行顺序对比 | 方式 | 执行阶段 | 特点 | |-----------------------|----------------------------------|--------------------------| | `@PostConstruct` | Bean初始化阶段 | 最早执行,但依赖未完全就绪 | | `@EventListener` | 应用上下文刷新完成后 | 精确监听特定启动事件 | | `ApplicationRunner` | 在启动事件之间 | 可访问结构化启动参数 | | `CommandLineRunner` | 同上 | 接收原始命令行参数 | | `@Scheduled` | 应用就绪后 | 适合延迟初始化任务 | ### 最佳实践建议 1. **关键初始化** → 使用 `@EventListener(ApplicationReadyEvent.class)` 确保完全就绪[^4] 2. **Bean依赖初始化** → 采用 `@PostConstruct` [^2] 3. **参数处理** → 选择 `ApplicationRunner` 或 `CommandLineRunner` 4. **避免阻塞**:启动任务执行时间超过 60 秒可能触发健康检查失败 > 示例:组合使用确保安全启动 > ```java > @EventListener(ApplicationStartedEvent.class) > public void initDBConnection() { > // 初始化数据库连接池 > } > > @EventListener(ApplicationReadyEvent.class) > public void checkServices() { > // 验证所有微服务是否可用 > } > ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值