1. 程式人生 > >springboot自帶定時器實現定時任務的開啟關閉以及動態修改定時規則

springboot自帶定時器實現定時任務的開啟關閉以及動態修改定時規則

最近專案中遇到了需要自動定時匯出的需求,使用者可以從頁面修改匯出的時間規則,可以啟用和停用定時任務。

經過了解,專案中目前實現定時任務,一般有三種選擇,一是用Java自帶的timer類。稍微看了一下,可以實現大部分的指定頻率的任務的排程(timer.schedule()),也可以實現關閉和開啟(timer.cancle)。但是用其來實現某天的某個時間或者某月的某一天排程任務有點不方便。

二是採用Quartz 排程器實現。這是一個功能很強大的開源的專門用於定時任務排程的框架,也很好的和springboot整合,缺點:配置複雜,需要花費一定的時間去了解和研究。(本人懶,因此沒有選擇這個,但是這個功能地區強大,有時間研究)

三是spring3.0以後自帶的scheduletask任務排程,可以實現quartz的大部分功能,不需要額外引用jar,也不需要另外配置。而且支援註解和配置檔案兩種。

因此最後選擇直接用spring自帶的task 實現。

基本用法很簡單,通過在方法上加註解@schedule(也可以通過xml檔案配置的方式),註解裡有 cron ,fixedDelay ,fixedRate ,initialDelay 等等引數,可以完成指定時間,平率執行此方法。這裡不詳細介紹。

直接介紹,通過頁面動態修改cron引數,修改定時規則的思路。

1 實現介面SchedulingConfigurer,這個介面只有一個方法,配置定時任務。重寫此方法,新增新的任務實現runable和新的觸發 實現trigger 。

2 在新的觸發裡,把修改的cron寫入新的觸發

3 寫UI  方法,接收前端修改的定時引數。

程式碼如下:

package com.fiberhome.ms.cus.cashform.ui;


import java.util.Date;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
@Component
public class DynamicScheduledTask implements SchedulingConfigurer {
@Autowired
private ScheduleExport scheduleExport;


// private static String DEFAULT_CRON = "0/10 * * * * ?";
private String cron = "";


public String getCron() {
return cron;
}


public void setCron(String cron) {
this.cron = cron;
}


@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// TODO Auto-generated method stub
taskRegistrar.addTriggerTask(new Runnable() {


@Override
public void run() {
// TODO Auto-generated method stub
try {
scheduleExport.scheduleTaskExport();//非同步定時生成檔案
System.out.println("Msg:定時生成檔案成功");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println("Error:定時生成檔案錯誤");
}
}
}, new Trigger() {

@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
// TODO Auto-generated method stub
if ("".equals(cron)|| cron == null)
return null;
CronTrigger trigger = new CronTrigger(cron);// 定時任務觸發,可修改定時任務的執行週期
Date nextExecDate = trigger.nextExecutionTime(triggerContext);
return nextExecDate;
}
});
System.out.println("can?");
}

}

這個方法可以實現 根據頁面設定動態修改定時器的cron引數,不用重啟服務。但是執行之後發現了一個缺陷,即必須在修改完之後,只有再一次到達定時任務的時間,才會呼叫新的觸發時間, 這就導致,頁面設定的時間並不能即時生效,這在專案中是不符合使用者的要求,於是為了解決這個bug,換了另外一種解決方法。

思路:(瞭解ThreadPoolTaskScheduler這個類,TaskScheduler介面的預設實現類,多執行緒定時任務執行。可以設定執行執行緒池數(預設一個執行緒))

1、ThreadPoolTaskScheduler 實現TaskScheduler,可以通過方法 schedule(java.lang.Runnable task, Trigger trigger),新增定時任務和觸發器。返回java.util.concurrent.ScheduledFuture<?>,future可以控制任務的開關等。

2、前端修改定時引數,在set方法中修改ThreadPoolTaskScheduler 的觸發器。

程式碼如下:

package com.fiberhome.ms.cus.cashform.ui.util;


import java.util.Date;
import java.util.concurrent.ScheduledFuture;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;


import com.fiberhome.ms.cus.cashform.ui.ScheduleExport;


@Component
public class DynamicScheduleTaskSecond {
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
@Autowired
private ScheduleExport scheduleExport;
private ScheduledFuture<?> future;


private String cron = "";


public String getCron() {
return cron;
}


public void setCron(String cron) {
this.cron = cron;
stopCron();
future = threadPoolTaskScheduler.schedule(new Runnable() {


@Override
public void run() {
// TODO Auto-generated method stub
try {
scheduleExport.scheduleTaskExport();// 非同步定時生成檔案
System.out.println("Msg:定時生成檔案成功");
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
System.out.println("Error:定時生成檔案錯誤");
}
}
}, new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
// TODO Auto-generated method stub
if ("".equals(cron) || cron == null)
return null;
CronTrigger trigger = new CronTrigger(cron);// 定時任務觸發,可修改定時任務的執行週期
Date nextExecDate = trigger.nextExecutionTime(triggerContext);
return nextExecDate;
}
});
}


public void stopCron() {
if (future != null) {
future.cancel(true);//取消任務排程
}
}
}

驗證可行,作個記錄,如果有認為可以調整的地方,歡迎討論!