Spring Boot启动后运行代码的方法
技术背景
在开发Spring Boot应用时,有时需要在应用启动后执行一些特定的代码,例如监控目录变化、初始化数据等。然而,直接在启动时运行代码可能会遇到@Autowired
服务未初始化的问题,因此需要找到合适的时机来执行这些代码。
实现步骤
1. 使用ApplicationReadyEvent
ApplicationReadyEvent
会在应用刷新并处理完所有相关回调后触发,表明应用已准备好处理请求。可以通过@EventListener
注解监听该事件。
1 2 3 4 5 6 7 8 9 10 11 12
| import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component;
@Component public class StartupRunner {
@EventListener(ApplicationReadyEvent.class) public void doSomethingAfterStartup() { System.out.println("hello world, I have just started up"); } }
|
2. 实现ApplicationListener<ApplicationReadyEvent>
接口
创建一个类实现ApplicationListener<ApplicationReadyEvent>
接口,并重写onApplicationEvent
方法。
1 2 3 4 5 6 7 8 9 10 11 12
| import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.ApplicationListener; import org.springframework.stereotype.Component;
@Component public class ApplicationStartup implements ApplicationListener<ApplicationReadyEvent> {
@Override public void onApplicationEvent(final ApplicationReadyEvent event) { } }
|
3. 使用CommandLineRunner
或ApplicationRunner
CommandLineRunner
和ApplicationRunner
是Spring Boot提供的接口,实现这些接口并重写run
方法,Spring Boot会在应用启动过程的末尾执行这些方法。
1 2 3 4 5 6 7 8 9 10 11
| import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component;
@Component public class CommandLineAppStartupRunner implements CommandLineRunner {
@Override public void run(String... args) throws Exception { System.out.println("Application started with command-line arguments: " + String.join(", ", args)); } }
|
4. 使用@PostConstruct
注解
在一个@Component
类中使用@PostConstruct
注解的方法会在Bean初始化完成后执行。
1 2 3 4 5 6 7 8 9 10 11
| import javax.annotation.PostConstruct; import org.springframework.stereotype.Component;
@Component public class Monitor {
@PostConstruct public void init() { } }
|
5. 使用SmartInitializingSingleton
在Spring 4.1及以上版本中,可以使用SmartInitializingSingleton
,它会在所有单例Bean初始化完成后回调。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import org.springframework.beans.factory.SmartInitializingSingleton; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration;
@Configuration public class AppConfig {
@Bean public SmartInitializingSingleton importProcessor() { return () -> { }; } }
|
核心代码
以下是几种方法的核心代码示例:
使用ApplicationReadyEvent
1 2 3 4 5 6 7 8 9 10 11 12
| import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; import org.springframework.stereotype.Component;
@Component public class StartupExample {
@EventListener(ApplicationReadyEvent.class) public void executeAfterStartup() { System.out.println("执行启动后任务"); } }
|
使用CommandLineRunner
1 2 3 4 5 6 7 8 9 10 11
| import org.springframework.boot.CommandLineRunner; import org.springframework.stereotype.Component;
@Component public class CommandLineExample implements CommandLineRunner {
@Override public void run(String... args) throws Exception { System.out.println("使用CommandLineRunner执行任务"); } }
|
使用@PostConstruct
1 2 3 4 5 6 7 8 9 10 11
| import javax.annotation.PostConstruct; import org.springframework.stereotype.Component;
@Component public class PostConstructExample {
@PostConstruct public void init() { System.out.println("使用@PostConstruct执行任务"); } }
|
最佳实践
- 如果代码需要在应用准备好处理请求后执行,推荐使用
ApplicationReadyEvent
。 - 如果需要处理命令行参数,可以使用
CommandLineRunner
或ApplicationRunner
。 - 如果代码是与Bean初始化相关的,可以使用
@PostConstruct
注解。 - 如果需要在所有单例Bean初始化完成后执行代码,可以使用
SmartInitializingSingleton
。
常见问题
@Autowired
服务未初始化:使用ApplicationReadyEvent
、CommandLineRunner
、ApplicationRunner
或SmartInitializingSingleton
可以确保@Autowired
服务已初始化。@PostConstruct
方法执行过早:@PostConstruct
方法在Bean初始化时执行,可能会在应用整体准备好之前执行。如果需要在应用准备好后执行,不建议使用该注解。ContextRefreshedEvent
多次触发:ContextRefreshedEvent
可能会多次触发,需要在代码中添加判断逻辑,避免重复执行。