如何停止使用@Scheduled注释启动的计划任务?

我使用Spring Framework的@Scheduled注释创建了一个简单的计划任务。

 @Scheduled(fixedRate = 2000)
 public void doSomething() {}

现在我想停止这个任务,当不再需要时。

我知道在这个方法开始时可以有一种方法来检查一个条件标志,但是这不会停止执行这个方法。

Spring提供了什么来阻止@Scheduled任务?


选项1:使用后处理器

提供ScheduledAnnotationBeanPostProcessor并显式调用应该停止调度的bean的postProcessBeforeDestruction(Object bean, String beanName)


选项2:维护一个目标豆的未来地图

private final Map<Object, ScheduledFuture<?>> scheduledTasks =
        new IdentityHashMap<>();

@Scheduled(fixedRate = 2000)
public void fixedRateJob() {
    System.out.println("Something to be done every 2 secs");
}

@Bean
public TaskScheduler poolScheduler() {
    return new CustomTaskScheduler();
}

class CustomTaskScheduler extends ThreadPoolTaskScheduler {

    @Override
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) {
        ScheduledFuture<?> future = super.scheduleAtFixedRate(task, period);

        ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task;
        scheduledTasks.put(runnable.getTarget(), future);

        return future;
    }

    @Override
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
        ScheduledFuture<?> future = super.scheduleAtFixedRate(task, startTime, period);

        ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task;
        scheduledTasks.put(runnable.getTarget(), future);

        return future;
    }
}

当必须停止调度bean时,可以查找映射以获取相应的Future ,并明确地取消它。


这个问题有点含糊不清

  • 当你说“停止这项任务”时,你的意思是停止以后可以恢复(如果是的话,以编程方式使用在同一应用程序中出现的条件或外部条件)?
  • 你是否在同一个环境中运行其他任务? (关闭整个应用程序而不是任务的可能性) - 您可以在这种情况下使用actuator.shutdown端点
  • 我最好的猜测是,您正在寻找以可恢复的方式使用同一应用中可能出现的条件来关闭任务。 我会试着根据这个假设来回答。

    这是我能想到的最简单的解决方案,但是我会做一些改进,比如早期返回,而不是如果 s是嵌套

    @Component
    public class SomeScheduledJob implements Job {
    
        private static final Logger LOGGER = LoggerFactory.getLogger(SomeScheduledJob.class);
    
        @Value("${jobs.mediafiles.imagesPurgeJob.enable}")
        private boolean imagesPurgeJobEnable;
    
        @Override
        @Scheduled(cron = "${jobs.mediafiles.imagesPurgeJob.schedule}")
        public void execute() {
    
            if(!imagesPurgeJobEnable){
                return;
            }
            Do your conditional job here...
       }
    

    上述代码的属性

    jobs.mediafiles.imagesPurgeJob.enable=true or false
    jobs.mediafiles.imagesPurgeJob.schedule=0 0 0/12 * * ?
    

    前段时间,我在我的项目中有这样的要求,即任何组件都应该能够创建新的计划任务或停止计划程序(所有任务)。 所以我做了这样的事情

    @Configuration
    @EnableScheduling
    @ComponentScan
    @Component
    public class CentralScheduler {
    
        private static AnnotationConfigApplicationContext CONTEXT = null;
    
        @Autowired
        private ThreadPoolTaskScheduler scheduler;
    
        public static CentralScheduler getInstance() {
            if (!isValidBean()) {
                CONTEXT = new AnnotationConfigApplicationContext(CentralScheduler.class);
            }
    
            return CONTEXT.getBean(CentralScheduler.class);
        }
    
        @Bean
        public ThreadPoolTaskScheduler taskScheduler() {
            return new ThreadPoolTaskScheduler();
        }
    
        public void start(Runnable task, String scheduleExpression) throws Exception {
            scheduler.schedule(task, new CronTrigger(scheduleExpression));
        }
    
        public void start(Runnable task, Long delay) throws Exception {
            scheduler.scheduleWithFixedDelay(task, delay);
        }
    
        public void stopAll() {
            scheduler.shutdown();
            CONTEXT.close();
        }
    
        private static boolean isValidBean() {
            if (CONTEXT == null || !CONTEXT.isActive()) {
                return false;
            }
    
            try {
                CONTEXT.getBean(CentralScheduler.class);
            } catch (NoSuchBeanDefinitionException ex) {
                return false;
            }
    
            return true;
        }
    }
    

    所以我可以做类似的事情

    Runnable task = new MyTask();
    CentralScheduler.getInstance().start(task, 30_000L);
    CentralScheduler.getInstance().stopAll();
    

    请记住,出于某些原因,我没有担心并发性。 否则应该有一些同步。

    链接地址: http://www.djcxy.com/p/50893.html

    上一篇: How to stop a scheduled task that was started using @Scheduled annotation?

    下一篇: Configuring diff tool with .gitconfig?