如何让Micronaut定时任务等待应用启动完成后再执行?
解决Micronaut定时任务提前执行问题
全局解决方案:代理调度器延迟任务启动
无需修改现有定时任务代码,通过自定义代理TaskScheduler,让所有定时任务等待应用完全启动(即输出指定启动日志的时刻)后再执行首次任务,后续按原配置周期运行。
步骤1:实现代理调度器
创建包装默认TaskScheduler的代理类,缓存启动完成前的任务,启动完成后统一执行:
import io.micronaut.context.annotation.Primary; import io.micronaut.scheduling.TaskScheduler; import jakarta.inject.Singleton; import java.time.Duration; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ScheduledFuture; @Singleton @Primary public class StartupAwareTaskScheduler implements TaskScheduler { private final TaskScheduler delegate; private final List<Runnable> pendingTasks = new ArrayList<>(); private volatile boolean started = false; public StartupAwareTaskScheduler(TaskScheduler delegate) { this.delegate = delegate; } @Override public ScheduledFuture<?> schedule(Runnable command) { if (started) { return delegate.schedule(command); } else { pendingTasks.add(command); return () -> false; } } @Override public ScheduledFuture<?> schedule(Runnable command, Duration delay) { if (started) { return delegate.schedule(command, delay); } else { pendingTasks.add(() -> delegate.schedule(command, delay)); return () -> false; } } @Override public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, Duration initialDelay, Duration period) { if (started) { return delegate.scheduleAtFixedRate(command, initialDelay, period); } else { pendingTasks.add(() -> delegate.scheduleAtFixedRate(command, Duration.ZERO, period)); return () -> false; } } @Override public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, Duration initialDelay, Duration delay) { if (started) { return delegate.scheduleWithFixedDelay(command, initialDelay, delay); } else { pendingTasks.add(() -> delegate.scheduleWithFixedDelay(command, Duration.ZERO, delay)); return () -> false; } } public void start() { if (!started) { started = true; pendingTasks.forEach(Runnable::run); pendingTasks.clear(); } } }
步骤2:监听启动完成事件
创建事件监听器,在应用输出启动完成日志后,触发代理调度器执行缓存任务:
import io.micronaut.context.event.ApplicationEventListener; import io.micronaut.runtime.server.event.ServerStartupEvent; import jakarta.inject.Singleton; @Singleton public class StartupListener implements ApplicationEventListener<ServerStartupEvent> { private final StartupAwareTaskScheduler taskScheduler; public StartupListener(StartupAwareTaskScheduler taskScheduler) { this.taskScheduler = taskScheduler; } @Override public void onApplicationEvent(ServerStartupEvent event) { taskScheduler.start(); } }
说明
ServerStartupEvent是Micronaut在服务器完全启动、输出你指定的启动完成日志后发布的事件,完全匹配需求。- 代理调度器会自动缓存启动完成前的所有定时任务,启动后立即执行首次任务,后续按原
@Scheduled注解配置的周期/延迟运行。 - 无需修改任何现有定时任务代码,全局生效,避免开发者遗漏。
内容的提问来源于stack exchange,提问作者Zonko
相关产品推荐
相关产品推荐

