美文网首页Spring-Boot
停止使用@Scheduled注解启动的任务

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

作者: 大哥你先走 | 来源:发表于2018-12-14 23:50 被阅读39次

    子曰:小胜靠智,大胜靠德,常胜靠身体。

    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()实现。可以从这里下载完整的样例代码。

    相关文章

      网友评论

        本文标题:停止使用@Scheduled注解启动的任务

        本文链接:https://www.haomeiwen.com/subject/mnanhqtx.html