Springboot实现动态定时/手动注入定时任务


 在Springboot中使用轻量级计划任务框架,实现静态定时任务、动态定时任务及手动注入定时任务。

首先,模块化定时任务配置类,作为定时任务入口:

 1 package cn.demo.support.config;
 2 
 3 import java.util.concurrent.Executor;
 4 import java.util.concurrent.Executors;
 5 import java.util.concurrent.ScheduledThreadPoolExecutor;
 6 
 7 import org.slf4j.Logger;
 8 import org.slf4j.LoggerFactory;
 9 import org.springframework.context.annotation.Bean;
10 import org.springframework.context.annotation.Configuration;
11 import org.springframework.scheduling.annotation.EnableScheduling;
12 import org.springframework.scheduling.annotation.SchedulingConfigurer;
13 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
14 import org.springframework.scheduling.config.ScheduledTaskRegistrar;
15 
16 import cn.jsfund.ngdp.support.batchSchedule.AutoRegistScheduleTask;
17 import cn.jsfund.ngdp.support.batchSchedule.HiveClusterAsync;
18 
19 /**
20  * 定时任务配置
21  * 
22  */
23 @EnableScheduling
24 @Configuration
25 public class ScheduleConfig implements SchedulingConfigurer {
26 
27     private static final Logger logger = LoggerFactory.getLogger(ScheduleConfig.class);
28 
29     @Bean
30     public HiveClusterAsync initHiveClusterAsync() {
31 
32         logger.info("开启Hive集群同步定时任务...");
33         return new HiveClusterAsync();//动态定时任务,扫库取crontab执行
34     }
35 
36     @Bean
37     public AutoRegistScheduleTask initAutoScheduler() {
38 
39         logger.info("开启自定义定时任务...");
40         return new AutoRegistScheduleTask();//一般定时
41     }
42 
43     //注入计划任务注册器
44     @Bean
45     public ScheduledTaskRegistrar scheduledTaskRegistrar() {
46 
47         return new ScheduledTaskRegistrar();
48     }
49 
50     @Override
51     public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
52         taskRegistrar.setScheduler(taskExecutor());
53     }
54 
55     /**
56      * 配置多线程执行定时任务,不配置的话,定时任务是默认单线程顺序执行
57      */
58     //        @Bean(destroyMethod = "shutdown")
59     //        public Executor taskExecutor() {
60     //            return Executors.newScheduledThreadPool(Runtime.getRuntime().availableProcessors() * 2);//return ScheduledThreadPoolExecutor
61     //        }
62 
63     //因为需要手动注入定时任务,连接池换成spring的 ThreadPoolTaskScheduler,调用其schedule(Runnable task, Trigger trigger)方法即可。此类封装了 jdk的ScheduledThreadPoolExecutor
64     @Bean(destroyMethod = "shutdown")
65     public ThreadPoolTaskScheduler taskExecutor() {
66         ThreadPoolTaskScheduler executor = new ThreadPoolTaskScheduler();
67         executor.setPoolSize(20);
68         executor.setThreadNamePrefix("taskExecutor-");
69         executor.setWaitForTasksToCompleteOnShutdown(true);
70         executor.setAwaitTerminationSeconds(60);
71         return executor;
72     }
73 }

1.静态定时任务

  若单线程执行定时任务,则可以不需要以上配置,启动类上加@EnableScheduling注解即可,然后定时类直接使用@Scheduled注解,:

 

 1 package cn.demo.support.batchSchedule;
 2 
 3 import org.slf4j.Logger;
 4 import org.slf4j.LoggerFactory;
 5 import org.springframework.scheduling.annotation.Scheduled;
 6 import org.springframework.scheduling.annotation.SchedulingConfigurer;
 7 import org.springframework.scheduling.config.ScheduledTaskRegistrar;
 8 import org.springframework.stereotype.Component;
 9 
10 import cn.jsfund.ngdp.support.web.service.bigdata.impl.HiveClusterAsyncServiceImpl;
11 
12 //@Component 不需要模块化入口类引入时,需加上此注解注入bean
13 public class AutoRegistScheduleTask {
14 
15     private static final Logger logger = LoggerFactory.getLogger(AutoRegistScheduleTask.class);
16 
17     @Scheduled(cron = "0/3 * * * * ?")
18     public void exeDemo1() throws Exception {
19         logger.info("开始执行1");
20         //do somthing
21         logger.info("执行1结束");
22     }
23 
24     @Scheduled(cron = "0/3 * * * * ?")
25     public void exeDemo2() throws Exception {
26         logger.info("开始执行2");
27         //do somthing
28         logger.info("执行2结束");
29     }
30 }

 

2.动态定时任务

  需要实现SchedulingConfigurer 接口,重写方法添加定时任务:

 1 package cn.demo.support.batchSchedule;
 2 
 3 import org.slf4j.Logger;
 4 import org.slf4j.LoggerFactory;
 5 import org.springframework.scheduling.annotation.SchedulingConfigurer;
 6 import org.springframework.scheduling.config.ScheduledTaskRegistrar;
 7 
 8 public class HiveClusterAsync implements SchedulingConfigurer {
 9 
10     private static final Logger logger = LoggerFactory.getLogger(HiveClusterAsync.class);
11 
12     @Override
13     public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
14 
15         //查库获取crongtab
16         String cron = "0/8 * * * * ?";
17         taskRegistrar.addCronTask(new Runnable() {
18 
19             public void run() {
20                 logger.info("动态定时任务开始...");
21                 //dosomething
22             }
23 
24         }, cron);
25         logger.info("添加定时任务完成");
26     }}

  或者使用addTriggerTask方法添加计划任务,区别是,addTriggerTask方法内的nextExecutionTime方法返回值为crontab匹配的下次执行时间,

  nextExecutionTime方法每次都会执行,可以修改其返回值,改变下次执行时间,

  比如使用场景为:多节点部署的代码,保证定时任务高可用,每个节点都需要刷新当前内存中注册的定时任务,我们就可使用定时刷新,但是刷新一定要不同步的,

  保证刷新时,其他节点能正常执行任务,因此,可以给下次执行时间每次都加个随机值,使多节点不同时间刷新计划任务;

 1 package cn.demo.support.batchSchedule;
 2 
 3 import java.util.Date;
 4 import java.util.Random;
 5 
 6 import javax.annotation.Resource;
 7 
 8 import org.slf4j.Logger;
 9 import org.slf4j.LoggerFactory;
10 import org.springframework.scheduling.Trigger;
11 import org.springframework.scheduling.TriggerContext;
12 import org.springframework.scheduling.annotation.SchedulingConfigurer;
13 import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
14 import org.springframework.scheduling.config.ScheduledTaskRegistrar;
15 import org.springframework.scheduling.support.CronTrigger;
16 import org.springframework.stereotype.Component;
17 
18 @Component
19 public class TimingRefreshHiveTask implements SchedulingConfigurer {
20 
21     @Resource
22     ThreadPoolTaskScheduler taskExecutor;
23 
24     public TimingRefreshHiveTask() {
25     }
26 
27     private static final Logger logger = LoggerFactory.getLogger(HiveClusterSyncScheduler.class);
28 
29     @Override
30     public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
31         taskRegistrar.setScheduler(taskExecutor);
32 
33         String crontab = "0/30 * * * * ?";
34 
35         taskRegistrar.addTriggerTask(new Runnable() {
36 
37             @Override
38             public void run() {
39                 logger.info("do something, eg: 刷新已注册的定时任务...");
40             }
41         }, new Trigger() {
42 
43             @Override
44             public Date nextExecutionTime(TriggerContext triggerContext) {
45                 Date date = new CronTrigger(crontab).nextExecutionTime(triggerContext);
46                 logger.info("已配置下次刷新时间为:" + date);
47 
48                 Date nexDate = new Date();
49                 nexDate.setTime((3 + new Random().nextInt(5)) * 1000 + date.getTime());//给每次执行时间随机+ 3~8秒
50                 logger.info("增加随机值后,下次刷新时间:" + nexDate);
51                 return nexDate;
52             }
53         });
54 
55     }
56 
57 }

系统启动后执行效果如下:可以看到下次执行时,按照修改后的时间执行。

[2021-04-07 17:32:41.042] INFO  [restartedMain] NgdpMgrApplication[line:34] - 当前节点:10.0.192.100
[2021-04-07 17:33:05.003] INFO  [taskExecutor-1] HiveClusterSyncScheduler[line:49] - do something, eg: 刷新已注册的定时任务...
[2021-04-07 17:33:05.004] INFO  [taskExecutor-1] HiveClusterSyncScheduler[line:56] - 已配置下次刷新时间为:Wed Apr 07 17:33:30 CST 2021
[2021-04-07 17:33:05.005] INFO  [taskExecutor-1] HiveClusterSyncScheduler[line:60] - 增加随机值后,下次刷新时间:Wed Apr 07 17:33:34 CST 2021
[2021-04-07 17:33:34.004] INFO  [taskExecutor-1] HiveClusterSyncScheduler[line:49] - do something, eg: 刷新已注册的定时任务...
[2021-04-07 17:33:34.005] INFO  [taskExecutor-1] HiveClusterSyncScheduler[line:56] - 已配置下次刷新时间为:Wed Apr 07 17:34:00 CST 2021
[2021-04-07 17:33:34.005] INFO  [taskExecutor-1] HiveClusterSyncScheduler[line:60] - 增加随机值后,下次刷新时间:Wed Apr 07 17:34:07 CST 2021
[2021-04-07 17:34:07.004] INFO  [taskExecutor-1] HiveClusterSyncScheduler[line:49] - do something, eg: 刷新已注册的定时任务...
[2021-04-07 17:34:07.005] INFO  [taskExecutor-1] HiveClusterSyncScheduler[line:56] - 已配置下次刷新时间为:Wed Apr 07 17:34:30 CST 2021
[2021-04-07 17:34:07.005] INFO  [taskExecutor-1] HiveClusterSyncScheduler[line:60] - 增加随机值后,下次刷新时间:Wed Apr 07 17:34:37 CST 2021

 

 

3.手动注入定时任务

业务类中引入ThreadPoolTaskScheduler 

@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;

调用其schedule方法,此方法和上面的addTriggerTask方法入参相同; 

String crontab = "0 48 16 * * ?";
threadPoolTaskScheduler.schedule(new Runnable() {
                @Override
                public void run() {
                    try {
                        //do something;
                    } catch (ServiceException e) {
                        logger.info("手动添加的任务计划执行失败,异常信息:", e);
                    }
                }
            }, new Trigger() {
                @Override
                public Date nextExecutionTime(TriggerContext triggerContext) {
                    return new CronTrigger(crontab).nextExecutionTime(triggerContext);
                }
            });

 

执行效果:

[2021-03-26 11:06:27.001] INFO  [pool-2-thread-4] AutoRegistScheduleTask[line:19] - 开始执行1
[2021-03-26 11:06:27.001] INFO  [pool-2-thread-5] AutoRegistScheduleTask[line:26] - 开始执行2
[2021-03-26 11:06:27.001] INFO  [pool-2-thread-4] AutoRegistScheduleTask[line:21] - 执行1结束
[2021-03-26 11:06:27.001] INFO  [pool-2-thread-5] AutoRegistScheduleTask[line:28] - 执行2结束
[2021-03-26 11:06:30.001] INFO  [pool-2-thread-4] AutoRegistScheduleTask[line:19] - 开始执行1
[2021-03-26 11:06:30.001] INFO  [pool-2-thread-7] AutoRegistScheduleTask[line:26] - 开始执行2
[2021-03-26 11:06:30.001] INFO  [pool-2-thread-4] AutoRegistScheduleTask[line:21] - 执行1结束
[2021-03-26 11:06:30.001] INFO  [pool-2-thread-7] AutoRegistScheduleTask[line:28] - 执行2结束
[2021-03-26 11:06:32.002] INFO  [pool-2-thread-6] HiveClusterAsync[line:55] - 动态定时任务开始...
[2021-03-26 11:06:33.002] INFO  [pool-2-thread-1] AutoRegistScheduleTask[line:19] - 开始执行1
[2021-03-26 11:06:33.002] INFO  [pool-2-thread-8] AutoRegistScheduleTask[line:26] - 开始执行2
[2021-03-26 11:06:33.002] INFO  [pool-2-thread-1] AutoRegistScheduleTask[line:21] - 执行1结束
[2021-03-26 11:06:33.003] INFO  [pool-2-thread-8] AutoRegistScheduleTask[line:28] - 执行2结束
[2021-03-26 11:06:36.001] INFO  [pool-2-thread-1] AutoRegistScheduleTask[line:19] - 开始执行1
[2021-03-26 11:06:36.001] INFO  [pool-2-thread-4] AutoRegistScheduleTask[line:26] - 开始执行2
[2021-03-26 11:06:36.001] INFO  [pool-2-thread-1] AutoRegistScheduleTask[line:21] - 执行1结束
[2021-03-26 11:06:36.001] INFO  [pool-2-thread-4] AutoRegistScheduleTask[line:28] - 执行2结束
[2021-03-26 11:06:39.000] INFO  [pool-2-thread-1] AutoRegistScheduleTask[line:19] - 开始执行1
[2021-03-26 11:06:39.000] INFO  [pool-2-thread-1] AutoRegistScheduleTask[line:21] - 执行1结束
[2021-03-26 11:06:39.000] INFO  [pool-2-thread-1] AutoRegistScheduleTask[line:26] - 开始执行2
[2021-03-26 11:06:39.000] INFO  [pool-2-thread-1] AutoRegistScheduleTask[line:28] - 执行2结束
[2021-03-26 11:06:40.001] INFO  [pool-2-thread-6] HiveClusterAsync[line:55] - 动态定时任务开始...

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM