启动时同步执行任务
1、直接在启动类下面调用方法
@SpringBootApplication
public class TestApplication {
public static void main(String[] args) {
SpringApplication.run(TestApplication.class, args);
System.out.println("在启动类添加初始下方法");
}
}
2、使用@PostConstruct注解
@Component
public class MyInitStart2 {
@PostConstruct
public void run() {
System.out.println("在MyInitStart2中添加初始下方法");
}
}
3、实现CommandLineRunner接口
@Component
public class MyInitStart3 implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("在MyInitStart3中添加初始下方法");
}
}
4、实现ApplicationRunner接口
@Component
public class MyInitStart4 implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("在MyInitStart4中添加初始下方法");
}
}
5、实现ApplicationListener接口
@Component
public class MyInitStart5 implements ApplicationListener<ApplicationStartedEvent> {
@Override
public void onApplicationEvent(ApplicationStartedEvent event) {
System.out.println("在MyInitStart5中添加初始下方法");
}
}
6、实现InitializingBean接口
@Component
public class MyInitStart6 implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("在MyInitStart6中添加初始下方法");
}
}
7、使用过滤器
@Component
public class MyFilter implements Filter {
/**
* init() :该方法在tomcat容器启动初始化过滤器时被调用,它在 Filter 的整个生命周期只会被调用一次。
* doFilter() :容器中的每一次请求都会调用该方法, FilterChain(放行) 用来调用下一个过滤器 Filter。
* destroy(): 当容器销毁过滤器实例时调用该方法,在方法中销毁或关闭资源,在过滤器 Filter 的整个生命周期也只会被调用一次。
*/
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("Filter 前置");
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("Filter 处理中");
filterChain.doFilter(servletRequest, servletResponse);
}
@Override
public void destroy() {
System.out.println("Filter 后置");
}
}
8、使用定时器方式
@Component
// 启用定时任务
@EnableScheduling
public class ScheduledTasks {
// 每 5 秒执行一次任务。
@Scheduled(cron = "0/5 * * * * ?")
public void performingTasks() {
System.out.println("在定时任务中添加初始化方法");
// 停止定时任务 代码实现省略...
}
}
以上几种方法的打印顺序:
- Filter 前置(过滤器)
- 在MyInitStart6中添加初始下方法(实现InitializingBean接口)
- 在MyInitStart2中添加初始下方法(使用@PostConstruct注解)
- 在MyInitStart5中添加初始下方法(实现ApplicationListener接口)
- 在MyInitStart3中添加初始下方法(实现CommandLineRunner接口)
- 在MyInitStart4中添加初始下方法(实现ApplicationRunner接口)
- 在启动类添加初始下方法(启动类)
- 在定时任务中添加初始化方法(定时任务)
启动时异步执行任务
使用 @Async + @EventListener
@Component
public class StartupAsyncTask {
private static final Logger log = LoggerFactory.getLogger(StartupAsyncTask.class);
@Async
@EventListener(ApplicationReadyEvent.class)
public void onApplicationEvent() {
log.info("应用启动完成,开始执行异步初始化任务...");
try {
// 模拟耗时任务
Thread.sleep(5000);
log.info("异步初始化任务执行完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
log.error("异步任务被中断", e);
}
}
}
使用 @Async + ApplicationRunner
@Component
@Slf4j
public class AsyncStartupRunner implements ApplicationRunner {
@Override
@Async
public void run(ApplicationArguments args) {
log.info("异步启动任务开始执行...");
// 执行初始化逻辑
initializeData();
loadCache();
preheatSystem();
log.info("异步启动任务执行完成");
}
private void initializeData() {
try {
Thread.sleep(2000);
log.info("数据初始化完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private void loadCache() {
try {
Thread.sleep(1500);
log.info("缓存预热完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private void preheatSystem() {
try {
Thread.sleep(1000);
log.info("系统预热完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
使用 CommandLineRunner + CompletableFuture
@Component
@Slf4j
public class AsyncCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) {
log.info("主线程继续执行,不等待异步任务");
// 使用 CompletableFuture 执行异步任务
CompletableFuture.runAsync(() -> {
log.info("CompletableFuture 异步任务开始");
try {
// 执行耗时初始化操作
performInitialization();
log.info("CompletableFuture 异步任务完成");
} catch (Exception e) {
log.error("异步任务执行失败", e);
}
});
}
private void performInitialization() {
try {
Thread.sleep(3000);
log.info("耗时初始化操作完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
}
使用 ApplicationListener + 线程池
@Component
@Slf4j
public class CustomAsyncStartupListener {
private final ExecutorService asyncExecutor = Executors.newFixedThreadPool(2);
@EventListener(ApplicationReadyEvent.class)
public void onApplicationReady(ApplicationReadyEvent event) {
log.info("应用启动完成,提交异步任务到线程池");
// 提交多个异步任务
asyncExecutor.submit(this::initTask1);
asyncExecutor.submit(this::initTask2);
// 关闭线程池(根据需要)
asyncExecutor.shutdown();
}
private void initTask1() {
try {
log.info("异步任务1开始执行");
Thread.sleep(2000);
log.info("异步任务1执行完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
private void initTask2() {
try {
log.info("异步任务2开始执行");
Thread.sleep(3000);
log.info("异步任务2执行完成");
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
@PreDestroy
public void destroy() {
if (!asyncExecutor.isShutdown()) {
asyncExecutor.shutdown();
}
}
}