停止使用@Scheduled注解启动的任务

本文介绍在Spring或SpringBoot中如何停止使用@Scheduled启动的定时任务。主要提供了两种方法:通过ScheduledAnnotationBeanPostProcessor关闭所有定时任务;通过ScheduledFuture对象取消指定的定时任务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

https://www.jianshu.com/p/f6d602603841
1 问题描述

在Spring或Spring Boot应用中如何停止使用@Scheduled启动的定时任务?

2 解决思路

在Spring中,使用@Scheduled启动的定时任务,Spring会构造对应的RunnableCallable对象并提交给ThreadPoolTaskScheduler执行,ThreadPoolTaskScheduler执行RunnableCallable会返回一个ScheduledFuture对象,通过ScheduledFuture对象的cancel()方法可以实现定时任务的停止。

3 解决方法

3.1 通过ScheduledAnnotationBeanPostProcessor关闭

ScheduledAnnotationBeanPostProcessorpostProcessBeforeDestruction方法可以停止使用@Scheduled启动的定时任务,该方法主要用于bean被销毁之前停止该bean的所有定时任务。因此,停止任务的另外一个可行方法是销毁bean,此方法过于简单粗暴,不推荐使用。

简单示例代码如下:

@Service
public class ScheduledProcessor implements ApplicationContextAware {
    private ApplicationContext context;
    private ScheduledAnnotationBeanPostProcessor processor;

    @PostConstruct
    public void initProcessor() {
        processor = (ScheduledAnnotationBeanPostProcessor) context.getBean("org.springframework.context.annotation.internalScheduledAnnotationProcessor");
    }

    public void stopTask(Object bean) {
        processor.postProcessBeforeDestruction(bean, null);
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }
}

上面的代码主要是通过ApplicationContext获取ScheduledAnnotationBeanPostProcessor并通过postProcessBeforeDestruction方法取消定时任务。

3.2 通过ScheduledFuture取消任务

通过提供自定义的ThreadPoolTaskScheduler实现,并覆写ThreadPoolTaskScheduler执行任务的方法,将返回的ScheduledFuture的对象和bean的映射关系存储到Map,然后通过bean获取ScheduledFuture对象来停止对应的任务。

下面是一段简单的实例代码:

@Service
public class CustomTaskScheduler extends ThreadPoolTaskScheduler {
    private final Map<Object, ScheduledFuture<?>> scheduledTasks = new IdentityHashMap<>();

    void cancelTask(Object identifier) {
        ScheduledFuture future = scheduledTasks.get(identifier);
        if (null != future) {
            System.out.println("future is not null");
            future.cancel(true);
        }
    }

    /**
     * call parent method and store the result Future for cancel task,
     * you can expand other method of you used.
     *
     * @param task   the task need to be executed
     * @param period the time between two continues execute
     * @return the result of task
     */
    @Override
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, long period) {
        ScheduledFuture<?> future = super.scheduleAtFixedRate(task, period);

        ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task;
        // Scheduled annotation only can used for no arguments method so hashCode plus method name is unique.
        scheduledTasks.put(runnable.getTarget(), future);

        return future;
    }

    /**
     * call parent method and store the result Future for cancel task,
     * you can expand other method of you used.
     *
     * @param task      the task need to be executed
     * @param startTime the task first executed time
     * @param period    the time between two continues execute
     * @return the result of task
     */
    @Override
    public ScheduledFuture<?> scheduleAtFixedRate(Runnable task, Date startTime, long period) {
        ScheduledFuture<?> future = super.scheduleAtFixedRate(task, startTime, period);

        ScheduledMethodRunnable runnable = (ScheduledMethodRunnable) task;
        // Scheduled annotation only can used for no arguments method so hashCode plus method name is unique.
        scheduledTasks.put(runnable.getTarget(), future);
        return future;
    }
}

ScheduledAnnotationBeanPostProcessor只能停止一个bean所有的任务,上面的方法可以精细的控制停止某一个确定的任务,读者可以思考一下如何实现?

总结

在Spring或Spring Boot中取消任务的方法就是通过任务返回的异步结果Future.cancel()实现。可以从这里下载完整的样例代码。



作者:大哥你先走
链接:https://www.jianshu.com/p/f6d602603841
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值