Springboot2模塊系列:Quartz(定時任務)

1 Quartz簡介

Quartz是執行定時任務的框架,由開源組織OpenSymphony在Job scheduling領域的開源項目,完全由java開發.
組成:

  • Job,JobDetail
    Job具體的業務邏輯類,JobDetail業務實例,實現多任務.
  • Trigger
    JobDetail觸發器,即執行任務的觸發條件(設定的時間,時間間隔和執行次數).包括SimpleTrigger和CronTrigger,SimpleTrigger爲簡單觸發條件,如執行時間和執行次數,CronTrigger可進一步設定執行週期,年月日時段.
  • Scheduler
    調度器,通過觸發器執行業務.

2 組件功能

2.1 Job

Job是Quartz中的一個接口,只有execute方法,在這個方法中編寫業務邏輯.

public interface Job{
	void execute(JobExecutionContext var1) throws JobExecutionException;
}

2.2 JobDetail

可理解爲Job的實例,每調用一個Job,通過JobDetail創建一個新的實例,Scheduler對JobDetail進行調度,可實現多定時任務.

  • JobBuilder
    實例化JobDetail,創建新的Job執行任務.

2.3 JobExecutionContext

包含Job的詳細參數,當Scheduler執行一個Job時,將JobExecutionContext傳遞給Job中的execute方法.

2.4 Trigger

觸發器,滿足觸發器條件,執行任務.

  • TriggerBuilder
    實例化觸發器.
  • SimpleTrigger
    觸發時間規則設定器,包括指定時間段內執行任務的次數.
  • CronTrigger
    觸發時間規則設定器,基於日曆的作業調度,可指定執行日期,日曆規則:
秒 分 小時 日 月 周 年
序號 時間字段 允許值 允許特殊字符
1 0-59 -*/
2 0-59 -*/
3 小時 0-23 -*/
4 1-31 -*?/LWC
5 月份 1-12或JAN-DEC -*/
6 1-7或SUN-SAT -*?/LC#
7 (可選)1970-2099 -*/

3 Usage

3.1 pom.xml

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-quartz</artifactId>
</dependency>

3.2 定時任務操作

package com.prjname.service;

import java.util.Map;
import org.quartz.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
@Transactional(rollbackFor = Exception.class)
public class TimerService{
    @Autowired 
    private Scheduler scheduler;
        
    public String buildTimerTask(Map taskInfos) throws Exception{
        String name = taskInfos.get("taskName").toString();
        String group = taskInfos.get("taskGroup").toString();
        String timeCycle = taskInfos.get("taskTimeCycle").toString();
        String classNameStr = taskInfos.get("className").toString();
        Class className = Class.forName(classNameStr);
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(timeCycle);
        JobDetail jobDetail = JobBuilder.newJob(className)
                                        .withIdentity(name, group)
                                        .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                                        .withIdentity(name, group)
                                        .startNow()
                                        .withSchedule(scheduleBuilder)
                                        .build();
        scheduler.scheduleJob(jobDetail, trigger);
        return "新建並啓動5秒的定時任務";
    }

    public String pauseTimerTask(Map taskInfos) throws Exception{
        String name = taskInfos.get("taskName").toString();
        String group = taskInfos.get("taskGroup").toString();
        JobKey jobKey = new JobKey(name, group);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if(jobDetail == null){
            return "定時任務不存在";
        }
        scheduler.pauseJob(jobKey);
        return "暫停定時任務"+name;
    }

    public String resumeTimerTask(Map taskInfos) throws Exception{
        String name = taskInfos.get("taskName").toString();
        String group = taskInfos.get("taskGroup").toString();
        JobKey jobKey= new JobKey(name, group);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey); 
        if(jobDetail == null){
            return "定時任務不存在";
        }
        scheduler.resumeJob(jobKey);
        return "恢復定時任務:"+name;
    }

    public String deleteTimerTask(Map taskInfos) throws Exception{
        String name = taskInfos.get("taskName").toString();
        String group = taskInfos.get("taskGroup").toString();
        JobKey jobKey = new JobKey(name, group);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if(jobDetail == null){
            return "定時任務不存在";
        }
        scheduler.deleteJob(jobKey);
        return "刪除定時任務:"+name;
    }
}

3.2.1 新建定時任務

public String buildTimerTask(Map taskInfos) throws Exception{
        String name = taskInfos.get("taskName").toString();
        String group = taskInfos.get("taskGroup").toString();
        String timeCycle = taskInfos.get("taskTimeCycle").toString();
        String classNameStr = taskInfos.get("className").toString();
        Class className = Class.forName(classNameStr);
        CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(timeCycle);
        JobDetail jobDetail = JobBuilder.newJob(className)
                                        .withIdentity(name, group)
                                        .build();
        Trigger trigger = TriggerBuilder.newTrigger()
                                        .withIdentity(name, group)
                                        .startNow()
                                        .withSchedule(scheduleBuilder)
                                        .build();
        scheduler.scheduleJob(jobDetail, trigger);
        return "新建並啓動5秒的定時任務";
    }

3.2.2 停止定時任務

public String pauseTimerTask(Map taskInfos) throws Exception{
        String name = taskInfos.get("taskName").toString();
        String group = taskInfos.get("taskGroup").toString();
        JobKey jobKey = new JobKey(name, group);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if(jobDetail == null){
            return "定時任務不存在";
        }
        scheduler.pauseJob(jobKey);
        return "暫停定時任務"+name;
    }

3.2.3 重啓定時任務

public String resumeTimerTask(Map taskInfos) throws Exception{
        String name = taskInfos.get("taskName").toString();
        String group = taskInfos.get("taskGroup").toString();
        JobKey jobKey= new JobKey(name, group);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey); 
        if(jobDetail == null){
            return "定時任務不存在";
        }
        scheduler.resumeJob(jobKey);
        return "恢復定時任務:"+name;
    }

3.2.4 刪除定時任務

 public String deleteTimerTask(Map taskInfos) throws Exception{
        String name = taskInfos.get("taskName").toString();
        String group = taskInfos.get("taskGroup").toString();
        JobKey jobKey = new JobKey(name, group);
        JobDetail jobDetail = scheduler.getJobDetail(jobKey);
        if(jobDetail == null){
            return "定時任務不存在";
        }
        scheduler.deleteJob(jobKey);
        return "刪除定時任務:"+name;
    }

3.2.5 定時任務傳參

新建定時任務時,可以傳遞參數,使用usingJobData屬性,操作如下:

JobDetail jobDetail = JobBuilder.newJob(className)
                                        .withIdentity(name, group)
                                        .usingJobData("params", params)
                                        .build();

3.3 定時任務執行業務邏輯

該部分爲定時任務定期執行的業務邏輯,本次以打印時間爲例,每隔5秒,打印一次當前時間。

package com.prjname.timer;

import java.text.SimpleDateFormat;
import java.util.Date;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.quartz.QuartzJobBean;

public class TestTimer extends QuartzJobBean{
    static Logger logger = LoggerFactory.getLogger(TestTimer.class);
    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException{
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date();
        String time = sdf.format(date);
        logger.info("定時時間:{}",time);
    }
}

3.4 控制器

package com.prjname.controller;

import com.xhwl.service.TimerService;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@CrossOrigin(origins="*", maxAge=3600)
@RestController
@RequestMapping("/api/v1")
public class TimerController{
    static Logger logger = LoggerFactory.getLogger(TimerController.class);
    @Autowired
    private TimerService timerService;

    @RequestMapping(value="/timer-task-creation", method=RequestMethod.POST)
    public Map createTimerTask(@RequestBody Map params){
        Map returnMap = new HashMap();
        try{
            String taskName = params.get("taskName").toString();
            String taskGroup = params.get("taskGroup").toString();
            String taskTimeCycle = params.get("taskCycle").toString();
            if(!taskName.equals("")|!taskGroup.equals("")|!taskTimeCycle.equals("")){
                Map<String, String> taskInfos = new HashMap<String, String>();
                taskInfos.put("taskName", taskName);
                taskInfos.put("taskGroup", taskGroup);
                taskInfos.put("taskTimeCycle", taskTimeCycle);
                taskInfos.put("className", "com.prjname.timer.TestTimer");
                String returnStr = timerService.startTimerTask(taskInfos);
                returnMap.put("code",200);
                returnMap.put("infos",returnStr);
                return returnMap;
            }else{
                returnMap.put("code",200);
                returnMap.put("infos","檢查參數");
                return returnMap;
            }
            
        }catch(Exception e){
            e.printStackTrace();
        }
        returnMap.put("code",400);
        returnMap.put("infos","檢查參數");
        return returnMap;
    }

    @RequestMapping(value="/timer-task-pause", method=RequestMethod.POST)
    public Map pauseTimerTask(@RequestBody Map params){
        Map returnMap = new HashMap();
        try{
            String taskName = params.get("taskName").toString();
            String taskGroup = params.get("taskGroup").toString();
            if(!taskName.equals("")|!taskGroup.equals("")){
                String returnStr = timerService.pauseTimerTask(params);
                returnMap.put("code", 200);
                returnMap.put("infos", returnStr);
                return returnMap;
            }else{
                returnMap.put("code", 400);
                returnMap.put("infos", "檢查參數");
                return returnMap;
            }
        }catch(Exception e){
            e.printStackTrace();
        }
        return returnMap;
    }
}

【參考文獻】
[1]https://www.jb51.net/article/160555.htm
[2]https://blog.csdn.net/noaman_wgs/article/details/80984873
[3]https://www.jianshu.com/p/056281e057b3
[4]https://www.cnblogs.com/knowledgesea/p/4705796.html
[5]https://www.cnblogs.com/bevis-byf/p/10087032.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章