Spring 框架自帶任務調度功能,比如一個輕量級的Quartz,使用簡單、方便,不須要依賴其餘JAR包。java
只須要在項目主程序啓動類上添加@EnableScheduling開啓任務調度功能便可數據庫
@SpringBootApplication @EnableScheduling public class LearnApplication { public static void main(String[] args) { SpringApplication.run(LearnApplication.class, args); } }
@Component public class TestTask { @Scheduled(cron = "0/10 * * * * *") public void testTask1() { System.out.println("【任務一】測試定時任務" + LocalDateTime.now()); } }
如上述,配置一個簡單的定時任務只須要在調度方法上添加@Shceduled註解便可,就可使用定時任務。markdown
@Component // 開啓異步支持 @EnableAsync public class TestTask { @Scheduled(cron = "0/10 * * * * *") // 方法使用異步執行,每次任務建立一個線程執行任務 @Async public void testTask1() { System.out.println("【任務一】測試定時任務" + LocalDateTime.now() + " " + Thread.currentThread().getName()); for (int i = 0; i < 20; i++) { try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("【任務一】休眠" + (i + 1) + "秒測試定時任務" + LocalDateTime.now() + " " + Thread.currentThread().getName()); } } }
每每在咱們的項目調度任務中,有的場景是須要在當前任務尚未執行完畢時,就須要執行下一個定時調度任務,在這種狀況下須要使用異步的方式來執行定時任務。框架
@EnableAsync開啓異步支持異步
@Async標記任務使用異步執行(下次任務將在下一個配置時間開始,不等待當前任務執行完畢)ide
當咱們編寫定時任務是,流程大體爲:編碼->配置執行週期->啓動服務。測試
當前咱們配置的執行週期是天天早上8點執行,當咱們有天,需求變動,須要天天晚上8點執行,咱們的操做流程爲:修改執行週期->新版打包->停服->啓動新版服務。整個流程線步驟多,存在不可控因素。編碼
那麼咱們怎麼作到不停服更新咱們的執行週期呢??線程
那麼下面咱們模擬將cron表達式存儲在MySQL。日誌
1)定義cron相關service
// 表達式相關接口 public interface SwitchService { /** * 獲取最新 cron 表達式 * * @param taskId 任務ID * @return 最新 cron表達式 */ String getCron(String taskId); /** * 修改 cron 表達式 */ void modify(); }
// 表達式相關接口實現 @Service public class SwitchServiceImpl implements SwitchService { private static String DB_CRON = ""; @Override public String getCron(String taskId) { System.out.println("執行數據庫查詢 DB_CRON " + LocalDateTime.now()); return DB_CRON; } @Override public void modify() { DB_CRON = "0/20 * * * * *"; System.out.println("修改數據庫中 DB_CRON " + LocalDateTime.now()); } }
此處模擬修改以及查詢
2)建立具體任務執行
@Component public class DynamicCronTask implements SchedulingConfigurer { // 模擬當前任務ID private String TASK_ID = "5001"; @Autowired private SwitchService switchService; private String SpringDynamicCronTask() { // 默認爲 每5秒執行 String cron = "0/5 * * * * ?"; //從數據庫得到配置的corn表達式 String dbCron = switchService.getCron(TASK_ID); // 當查詢爲空時,使用默認的表達式 if (StringUtils.isNotBlank(dbCron)) { return dbCron; } return cron; } @Override public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) { scheduledTaskRegistrar.addTriggerTask(new Runnable() { @Override public void run() { // 任務邏輯 System.out.println("執行任務邏輯...." + LocalDateTime.now()); } }, new Trigger() { @Override public Date nextExecutionTime(TriggerContext triggerContext) { String s = SpringDynamicCronTask(); // 任務觸發,可修改任務的執行週期 CronTrigger trigger = new CronTrigger(s); Date nextExec = trigger.nextExecutionTime(triggerContext); return nextExec; } }); } }
3)啓動服務
查看執行日誌
執行數據庫查詢 DB_CRON 2020-06-09T10:33:30.001 執行任務邏輯....2020-06-09T10:33:35.002 執行數據庫查詢 DB_CRON 2020-06-09T10:33:35.002 執行任務邏輯....2020-06-09T10:33:40.001 執行數據庫查詢 DB_CRON 2020-06-09T10:33:40.001 修改數據庫中 DB_CRON 2020-06-09T10:33:42.085 執行任務邏輯....2020-06-09T10:33:45 執行數據庫查詢 DB_CRON 2020-06-09T10:33:45 執行任務邏輯....2020-06-09T10:34:00.001 執行數據庫查詢 DB_CRON 2020-06-09T10:34:00.001 執行任務邏輯....2020-06-09T10:34:20.002 執行數據庫查詢 DB_CRON 2020-06-09T10:34:20.002
經過日誌能夠看出,在應用啓動時,會首先從數據庫中查詢配置的執行週期,而後執行定時任務,執行完畢後會再次查詢執行週期,下一個執行時間結束後就會按照修改的執行時間執行。
生效時間爲下一個執行時間結束後,作不到當即生效!!!