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