SpringMVC java 使用quartz實現靈活的定時任務

引言

最近項目中有這樣一個業務,相信你們也常常遇到。就是用戶經過前端設置了某年某月某日的定時任務,後臺接收而且定時執行。這個定時能夠經過前端UI改變,或者刪除,因此後端也須要作三個事,1-添加定時任務,2-修改定時任務時間,3-刪除定時任務。
前端

Spring的定時任務

Spring經過@Scheduled註解爲定時任務,cron表達式裏寫執行的時機,確實可以定時執行某個方法,可是卻沒辦法靈活的管理任務的添加,改變,丟棄。因此不知足咱們的需求。java

@Scheduled(cron="0/10 * * * * ? ")   //每10秒執行一次    
複製代碼

自定義org.quartz.Scheduler.Scheduler實現靈活定時任務管理

1. 建一個Scheduler的包裝類,提供單例實例的獲取

這裏生成一個Scheduler的包裝類,而且只返回自身的單例。並經過getScheduler()獲取到Scheduler的實例,這裏也保證他它是單例。後端


SchedulerController.javabash

public class SchedulerController {
    private static SchedulerController own;
    private Scheduler myScheduler;
    HashMap<String, TriggerKey> triggers = new HashMap<String, TriggerKey>();
    HashMap<String, JobKey> jobs = new HashMap<String, JobKey>();
    
    private SchedulerController() {
    }
    
    // 單例模式
    public static SchedulerController getInstance() {
        return own = Optional.ofNullable(own).orElse(new SchedulerController());
    }

    private Scheduler getScheduler() {
        try {
            myScheduler = Optional.ofNullable(myScheduler).orElse(new StdSchedulerFactory().getScheduler());
        } catch (SchedulerException e) {
            throw new RuntimeException(e);
        }
        return myScheduler;
    }
}

複製代碼

2.新建任務註冊到Scheduler並啓動

經過addJob()方法添加任務,接收的是一個Job類的實現類。startScheduler()啓動任務。其中添加任務分爲幾步。ide

  • 生成一個JobDetail類的實例,封裝你的任務細節。包含了一個JobKey描述任務名跟任務組。
  • 生成一個Trigger觸發器的實例,封裝你的定時時間。包含了一個TriggerKey描述任務名跟任務組。
  • 把JobDetail跟Trigger註冊到你的Scheduler中。

SchedulerController.java測試

public Scheduler addJob(ScheduleJob job, String cron) {

    Scheduler s = getScheduler();
    
    // jobDetail生成
    JobKey jobKey = new JobKey(job.getJobName(), job.getJobGroup());
    jobs.put(job.getJobName(), jobKey);
    JobDetail jobDetail = JobBuilder.newJob(job.getClass()).withIdentity(jobKey).build();
    
    // trigger生成
    TriggerKey triggerKey = new TriggerKey(job.getJobName(), job.getTriggerGroup());
    triggers.put(job.getJobName(), triggerKey);
    Trigger trigger = TriggerBuilder.newTrigger().withIdentity(triggerKey)
            .withSchedule(CronScheduleBuilder.cronSchedule(cron)).build();
    
    try {
        s.scheduleJob(jobDetail, trigger);
    } catch (SchedulerException e) {
        throw new RuntimeException(e);
    }

    return s;
}

public void startScheduler() {
    try {
        if (myScheduler != null && !myScheduler.isShutdown()) {
            myScheduler.start();
        }
    } catch (SchedulerException e) {
        throw new RuntimeException(e);
    }
}

複製代碼

ScheduleJob.javaui

@Data
public class ScheduleJob implements Job {
    private String jobName;
    private String jobGroup;
    private String triggerGroup;
    
    public ScheduleJob() {
        
    }
    
    public ScheduleJob(String jobName) {
        this.jobName = jobName;
    }
    
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        // 實際執行內容
        System.out.println("test");
    }
}
複製代碼

3.修改任務時間,刪除任務

上面說了任務時間是封裝到Trigger觸發器總的,因此修改任務的核心代碼在於CronTriggerImpl#setCronExpression(),來重設時間,再經過Scheduler#rescheduleJob()來重置。

刪除任務則是Scheduler#unscheduleJob()跟Scheduler#deleteJob()。this


SchedulerController.javaspa

public void modifyJobTime(String jobName, String cronExpression) {
    try {
        if (myScheduler == null) {
            return;
        }
        
        TriggerKey triggerKey = getTriggerKeyByName(jobName);

        CronTriggerImpl trigger = (CronTriggerImpl) myScheduler.getTrigger(triggerKey);
        if (trigger == null) {
            return;
        }
        
        String oldTime = trigger.getCronExpression();
        
        if (!oldTime.equalsIgnoreCase(cronExpression)) {
            try {
                trigger.setCronExpression(cronExpression);
            } catch (ParseException e) {
                throw new RuntimeException(e);
            }
            myScheduler.rescheduleJob(triggerKey, trigger);
        }
    } catch (SchedulerException e) {
        throw new RuntimeException(e);
    }
}

public void removeJob(String jobName) {
    try {
        myScheduler.pauseTrigger(getTriggerKeyByName(jobName));
        myScheduler.unscheduleJob(getTriggerKeyByName(jobName));
        myScheduler.deleteJob(getJobByName(jobName));
    } catch (SchedulerException e) {
        throw new RuntimeException(e);
    }
}


private TriggerKey getTriggerKeyByName(String jobName) {
    if (!triggers.containsKey(jobName)) {
        throw new RuntimeException(msg.getMessage("triggerNotExist", new String[] { jobName }, null));
    }

    return triggers.get(jobName);
}


private JobKey getJobByName(String jobName) {
    if (!jobs.containsKey(jobName)) {
        throw new RuntimeException(msg.getMessage("jobNotExist", new String[] { jobName }, null));
    }
    
    return jobs.get(jobName);
}

複製代碼

4.測試一下

先每隔一秒實行job,而後改成兩秒,最後刪除任務。code

SchedulerController sc = SchedulerController.getInstance();
sc.addJob(new ScheduleJob("Test"), "*/1 * * * * ?");
sc.startScheduler();
try {
	Thread.sleep(1000 * 5);
} catch (InterruptedException e) {
	e.printStackTrace();
}

sc.modifyJobTime("Test", "*/2 * * * * ?");

sc.removeJob("Test");
複製代碼

總結

自定義定時任務比較複雜,可是學會了後可以靈活的處理定時任務。

相關文章
相關標籤/搜索