Quartz 快速入门案例,看这一篇就够了
前言
Quartz 是基于 Java 實現的任務調度框架,對任務的創建、修改、刪除、觸發以及監控這些操作直接提供了 api,這意味著開發人員擁有最大的操作權,也帶來了更高的靈活性。
什么是任務調度?
任務調度指在將來某個特定的時間、固定的時間周期或規律變化的時間周期到達時自動調度并執行指定的任務。
文章稍長,建議點贊收藏😉,點擊跳轉目錄👉 SpringBoot 整合 Quartz 👇
一、Quartz 是什么?
Quartz 是一個開源的作業調度框架,它完全由 Java 寫成,并設計用于 J2SE 和 J2EE 應用中。它提供了巨大的靈活性而不犧牲簡單性。你能夠用它來為執行一個作業而創建簡單的或復雜的調度。它有很多特征,如:數據庫支持,集群,插件,EJB 作業預構建,JavaMail 及其它,支持 cron-like 表達式等等。
官網地址👉 http://www.quartz-scheduler.org
示例代碼:
import org.quartz.Scheduler; import org.quartz.SchedulerException; import org.quartz.impl.StdSchedulerFactory;public class QuartzTest {public static void main(String[] args) {try {// Grab the Scheduler instance from the Factory Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// and start it offscheduler.start();scheduler.shutdown();} catch (SchedulerException se) {se.printStackTrace();}} }在start()和shutdown()之間可以執行一些操作
// define the job and tie it to our HelloJob class JobDetail job = JobBuilder.newJob(HelloJob.class).withIdentity("job1", "group1").build();// Trigger the job to run now, and then repeat every 40 seconds Trigger trigger=TriggerBuilder.newTrigger().withIdentity("trigger1", "group1").startNow().withSchedule(SimpleScheduleBuilder.simpleSchedule().withIntervalInSeconds(40).repeatForever()) .build();// Tell quartz to schedule the job using our trigger scheduler.scheduleJob(job, trigger);二、核心概念
| Scheduler | 與調度程序交互的主要API |
| Job | 你想要調度器執行的任務組件需要實現的接口 |
| JobDetail | 用于定義作業的實例 |
| Trigger | 定義執行給定作業的計劃的組件 |
| JobBuilder | 用于定義/構建 JobDetail 實例,用于定義作業的實例 |
| TriggerBuilder | 用于定義/構建觸發器實例 |
1.任務Job
我們想要調度的任務都必須實現 org.quartz.job 接口,然后實現接口中定義的 execute( ) 方法
代碼如下(示例):
@Slf4j public class HelloJob implements Job {@Overridepublic void execute(JobExecutionContext context) {log.info("Hello Job 執行時間: {}", DateUtil.now());} }那么如何給job實例增加屬性或配置呢?如何在job的多次執行中,跟蹤job的狀態呢?
答案就是 JobDataMap,JobDetail對象的一部分。
JobDataMap 可以包含不限量的(序列化的)數據對象,在 job 實例執行的時候,可以使用其中的數據;
JobDataMap 是 Java Map接口的一個實現,額外增加了一些便于存取基本類型的數據的方法。
如下示例:
// define the job and tie it to our DumbJob classJobDetail job = newJob(DumbJob.class).withIdentity("myJob", "group1") // name "myJob", group "group1".usingJobData("jobSays", "Hello World!").usingJobData("myFloatValue", 3.141f).build(); public class HelloJob implements Job {public HelloJob() {}public void execute(JobExecutionContext context)throws JobExecutionException{JobKey key = context.getJobDetail().getKey();JobDataMap dataMap = context.getJobDetail().getJobDataMap();String jobSays = dataMap.getString("jobSays");float myFloatValue = dataMap.getFloat("myFloatValue");System.err.println("Instance " + key + " of HelloJob says: " + jobSays + ", and val is: " + myFloatValue);} }Job 狀態
在調用 execute 方法之前都會創建一個新的 Job 實例,這就牽引出了 Job 狀態的概念
| 無狀態的 Job | 每次調用時都會創建一個新的 JobDataMap |
| 有狀態的 Job | 多次 Job 調用可以持有一些狀態信息,這些狀態信息存儲在 JobDataMap 中 |
跟蹤 Job狀態時,需要在任務類上加個注解@PersistJobDataAfterExecution,讓 Job 變成有狀態
@Slf4j @PersistJobDataAfterExecution public class HelloJob implements Job {private Integer executeCount;public void setExecuteCount(Integer executeCount) {this.executeCount = executeCount;}@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {String data = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));log.info("execute count: {}, current time: {}",++executeCount, data);//將累加的 count 存入JobDataMap中jobExecutionContext.getJobDetail().getJobDataMap().put("executeCount", executeCount);} } /** OUTPUT: execute count: 1, current time: 2020-11-17 22:28:48 execute count: 2, current time: 2020-11-17 22:28:52 execute count: 3, current time: 2020-11-17 22:28:57 **/2.觸發器 Trigger
Trigger 作為執行任務的調度器。我們如果想要凌晨1點執行備份數據的任務,那么 Trigger 就會設置凌晨1點執行該任務。其中 Trigger 又分為 SimpleTrigger 和 CronTrigger 兩種,通過一個 TriggerKey 唯一標識
公共屬性
| JobKey | 表示job實例的標識,觸發器被觸發時,該指定的job實例會執行 |
| StartTime | 表示觸發器的時間表 首次被觸發的時間,值類型是Java.util.Date |
| EndTime | 指定觸發器的不再觸發的時間,它的值類型是Java.util.Date |
優先級(priority)
如果 Trigger 有多個,你可以為 Trigger 設置 priority(優先級) 屬性(priority屬性的值可以是任意整數,正數、負數),優先級高的 Trigger 會被首先觸發,如果沒有為trigger設置優先級,trigger使用默認優先級,值為5;
PS:🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧
- 只有同時觸發的trigger之間才會比較優先級。10:59觸發的trigger總是在11:00觸發的trigger之前執行。
- 如果trigger是可恢復的,在恢復后再調度時,優先級與原trigger是一樣的。
🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧🚧
SimpleTrigger 及 CronTrigger
| SimpleTrigger | 在一個指定時間段內執行一次作業任務或是在指定時間間隔內執行多次作業任務 |
| CronTrigger | 基于日歷的作業調度器,Cron表達式配置CronTrigger的實例,而不是像SimpleTrigger那樣精確指定間隔時間,比SimpleTrigger更常用 |
SimpleTrigger
SimpleTrigger 對于設置和使用是最為簡單的一種 QuartzTrigger,它是為那種需要在特定的日期/時間啟動,且以一個可能的間隔時間重復執行 n 次的 Job任務 所設計的。
比如我想要在一個指定的時間段內執行一次任務,我們只需要這樣寫:
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("testTrigger", "testTriggerGroup").startAt(startTime) //自定義執行時間.build();再者我想在指定的時間間隔內多次執行該任務,我們可以這樣寫:
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("testTrigger", "testTriggerGroup").withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).withRepeatCount(2)) // 每5秒執行一次,連續執行3次后停止,從 0 開始計數.build();我們來總結一下上面的示例:
-
SimpleTrigger具備的屬性有:開始時間、結束時間、重復次數和重復的時間間隔
-
重復次數的值可以為 0、正整數、或常量 SimpleTrigger.REPEAT_INDEFINITELY
-
重復的時間間隔屬性值必須大于 0 或長整型的正整數,以 毫秒 作為時間單位,當重復的時間間隔為 0 時,意味著與 Trigger 同時觸發執行
-
結束時間和重復次數同時存在時,以結束時間優先
CronTrigger
跟 SimpleTrigger 執行間隔時間觸發的相比,CronTrigger 更加靈活,它是基于日歷的作業調度器。使用 CronTrigger 我們可以執行某個時間點執行,例如 “每天的凌晨1點執行”、“每個工作日的 12 點執行”,也可以像 SimpleTrigger 那樣執行一個開始時間和結束時間運行任務
Cron表達式 是用來配置 CronTrigger 實例,它是一個由 7 個子表達式組成的字符串(在線Cron表達式生成器)
使用示例
Trigger trigger = TriggerBuilder.newTrigger().withIdentity("testTrigger", "testTriggerGroup").withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * 6 4 ?")).build();3.實例 JobDetail
Quartz 在每次執行 Job 時,都重新創建一個 Job 實例,所以它不直接接受一個 Job 的實例,相反它接收一個 Job 實現類。描述 Job 的實現類及其它相關的靜態信息,如 Job 名字、描述等。
JobDetail 為 Job 實例提供了許多設置屬性(name、group、jobClasS、jobDataMap),以及 JobDetaMap 成員變量屬性,它用來存儲特定Job實例的狀態信息,調度器需要借助 JobDetail 對象來添加 Job 實例。
4.調度器 Scheduler
Scheduler為任務的調度器,它會將任務 job 及觸發器 Trigger 整合起來,負責基于 Trigger 設定的時間來執行 Job。
三、體系結構
四、SpringBoot 整合 Quartz
上面我們大概介紹了 Quartz,那么該如何使用了,請往下看:
1.引入依賴
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-quartz</artifactId> </dependency>2.Quartz 配置
quartz:# 參見 org.springframework.boot.autoconfigure.quartz.QuartzPropertiesjob-store-type: jdbcwait-for-jobs-to-complete-on-shutdown: truescheduler-name: SpringBootDemoSchedulerproperties:org.quartz.threadPool.threadCount: 5org.quartz.threadPool.threadPriority: 5org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: trueorg.quartz.jobStore.misfireThreshold: 5000org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTXorg.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate# 在調度流程的第一步,也就是拉取待即將觸發的triggers時,是上鎖的狀態,即不會同時存在多個線程拉取到相同的trigger的情況,也就避免的重復調度的危險。org.quartz.jobStore.acquireTriggersWithinLock: true| RAMJobStore | 將其所有數據保存在RAM中,是使用最簡單的JobStore,它也是性能最高的(在CPU時間方面 |
| JDBCJobStore | 通過JDBC將其所有數據保存在數據庫中 |
說明: 🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶
- JDBCJobStore幾乎與任何數據庫一起使用,已被廣泛應用于Oracle,PostgreSQL,MySQL,MSSQLServer,HSQLDB和DB2。
- 要使用JDBCJobStore,必須首先創建一組數據庫表以供Quartz使用。
- 可以在Quartz發行版的docs/dbTables目錄中找到表創建SQL腳本
🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶🪶
3.自定義任務
HelloJob.java
@Slf4j public class HelloJob implements Job {@Overridepublic void execute(JobExecutionContext context) {log.info("Hello Job 執行時間: {}", DateUtil.now());} }TestJob.java
@Slf4j public class TestJob implements Job {@Overridepublic void execute(JobExecutionContext context) {log.info("Hello Job 執行時間: {}", DateUtil.now());} }4.實現動態管理定時任務
對任務的暫停、恢復、刪除等操作,只需調用Scheduler 的對應方法即可
JobKey jobKey = JobKey.jobKey(“jobName”, “jobGroup”);
scheduler.pauseJob(jobKey);//暫停任務
scheduler.resumeJob(jobKey);//恢復任務
scheduler.deleteJob(jobKey);//刪除任務
封裝任務調度類
JobForm.java
@Data public class JobForm {/*** 定時任務全類名*/@NotBlank(message = "類名不能為空")private String jobClassName;/*** 任務組名*/@NotBlank(message = "任務組名不能為空")private String jobGroupName;/*** 定時任務cron表達式*/@NotBlank(message = "cron表達式不能為空")private String cronExpression; }JobService.java
public interface JobService {/*** 添加并啟動定時任務** @param form 表單參數 * @throws Exception 異常*/void addJob(JobForm form) throws Exception;/*** 刪除定時任務** @param form 表單參數 * @throws SchedulerException 異常*/void deleteJob(JobForm form) throws SchedulerException;/*** 暫停定時任務** @param form 表單參數 * @throws SchedulerException 異常*/void pauseJob(JobForm form) throws SchedulerException;/*** 恢復定時任務** @param form 表單參數 * @throws SchedulerException 異常*/void resumeJob(JobForm form) throws SchedulerException;/*** 重新配置定時任務** @param form 表單參數 * @throws Exception 異常*/void cronJob(JobForm form) throws Exception;/*** 查詢定時任務列表** @param currentPage 當前頁* @param pageSize 每頁條數* @return 定時任務列表*/PageInfo<JobAndTrigger> list(Integer currentPage, Integer pageSize); }JobServiceImpl.java
@Service @Slf4j public class JobServiceImpl implements JobService {private final Scheduler scheduler;private final JobMapper jobMapper;@Autowiredpublic JobServiceImpl(Scheduler scheduler, JobMapper jobMapper) {this.scheduler = scheduler;this.jobMapper = jobMapper;}/*** 添加并啟動定時任務*{@link JobForm}* @return * @throws Exception 異常*/@Overridepublic void addJob(JobForm form) throws Exception {// 啟動調度器scheduler.start();// 構建Job信息JobDetail jobDetail = JobBuilder.newJob(JobUtil.getClass(form.getJobClassName()).getClass()).withIdentity(form.getJobClassName(), form.getJobGroupName()).build();// Cron表達式調度構建器(即任務執行的時間)CronScheduleBuilder cron = CronScheduleBuilder.cronSchedule(form.getCronExpression());//根據Cron表達式構建一個TriggerCronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(form.getJobClassName(), form.getJobGroupName()).withSchedule(cron).build();try {scheduler.scheduleJob(jobDetail, trigger);} catch (SchedulerException e) {log.error("【定時任務】創建失敗!", e);throw new Exception("【定時任務】創建失敗!");}}/*** 刪除定時任務*{@link JobForm}* @throws SchedulerException 異常*/@Overridepublic void deleteJob(JobForm form) throws SchedulerException {scheduler.pauseTrigger(TriggerKey.triggerKey(form.getJobClassName(), form.getJobGroupName()));scheduler.unscheduleJob(TriggerKey.triggerKey(form.getJobClassName(), form.getJobGroupName()));scheduler.deleteJob(JobKey.jobKey(form.getJobClassName(), form.getJobGroupName()));}/*** 暫停定時任務*{@link JobForm}* @throws SchedulerException 異常*/@Overridepublic void pauseJob(JobForm form) throws SchedulerException {scheduler.pauseJob(JobKey.jobKey(form.getJobClassName(), form.getJobGroupName()));}/*** 恢復定時任務*{@link JobForm}* @throws SchedulerException 異常*/@Overridepublic void resumeJob(JobForm form) throws SchedulerException {scheduler.resumeJob(JobKey.jobKey(form.getJobClassName(), form.getJobGroupName()));}/*** 重新配置定時任務*{@link JobForm}* @throws Exception 異常*/@Overridepublic void cronJob(JobForm form) throws Exception {try {TriggerKey triggerKey = TriggerKey.triggerKey(form.getJobClassName(), form.getJobGroupName());// 表達式調度構建器CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(form.getCronExpression());CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);// 根據Cron表達式構建一個Triggertrigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();// 按新的trigger重新設置job執行scheduler.rescheduleJob(triggerKey, trigger);} catch (SchedulerException e) {log.error("【定時任務】更新失敗!", e);throw new Exception("【定時任務】創建失敗!");}}/*** 查詢定時任務列表** @param currentPage 當前頁* @param pageSize 每頁條數* @return 定時任務列表*/@Overridepublic PageInfo<JobAndTrigger> list(Integer currentPage, Integer pageSize) {PageHelper.startPage(currentPage, pageSize);List<JobAndTrigger> list = jobMapper.list();return new PageInfo<>(list);} }任務調度接口
JobController.java
@RestController @RequestMapping("/job") @Slf4j public class JobController {private final JobService jobService;@Autowiredpublic JobController(JobService jobService) {this.jobService = jobService;}/*** 保存定時任務*/@PostMappingpublic ResponseEntity<ApiResponse> addJob(@Valid JobForm form) {try {jobService.addJob(form);} catch (Exception e) {return new ResponseEntity<>(ApiResponse.msg(e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);}return new ResponseEntity<>(ApiResponse.msg("操作成功"), HttpStatus.CREATED);}/*** 刪除定時任務*/@DeleteMappingpublic ResponseEntity<ApiResponse> deleteJob(JobForm form) throws SchedulerException {if (StrUtil.hasBlank(form.getJobGroupName(), form.getJobClassName())) {return new ResponseEntity<>(ApiResponse.msg("參數不能為空"), HttpStatus.BAD_REQUEST);}jobService.deleteJob(form);return new ResponseEntity<>(ApiResponse.msg("刪除成功"), HttpStatus.OK);}/*** 暫停定時任務*/@PutMapping(params = "pause")public ResponseEntity<ApiResponse> pauseJob(JobForm form) throws SchedulerException {if (StrUtil.hasBlank(form.getJobGroupName(), form.getJobClassName())) {return new ResponseEntity<>(ApiResponse.msg("參數不能為空"), HttpStatus.BAD_REQUEST);}jobService.pauseJob(form);return new ResponseEntity<>(ApiResponse.msg("暫停成功"), HttpStatus.OK);}/*** 恢復定時任務*/@PutMapping(params = "resume")public ResponseEntity<ApiResponse> resumeJob(JobForm form) throws SchedulerException {if (StrUtil.hasBlank(form.getJobGroupName(), form.getJobClassName())) {return new ResponseEntity<>(ApiResponse.msg("參數不能為空"), HttpStatus.BAD_REQUEST);}jobService.resumeJob(form);return new ResponseEntity<>(ApiResponse.msg("恢復成功"), HttpStatus.OK);}/*** 修改定時任務,定時時間*/@PutMapping(params = "cron")public ResponseEntity<ApiResponse> cronJob(@Valid JobForm form) {try {jobService.cronJob(form);} catch (Exception e) {return new ResponseEntity<>(ApiResponse.msg(e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);}return new ResponseEntity<>(ApiResponse.msg("修改成功"), HttpStatus.OK);}@GetMappingpublic ResponseEntity<ApiResponse> jobList(Integer currentPage, Integer pageSize) {if (ObjectUtil.isNull(currentPage)) {currentPage = 1;}if (ObjectUtil.isNull(pageSize)) {pageSize = 10;}PageInfo<JobAndTrigger> all = jobService.list(currentPage, pageSize);return ResponseEntity.ok(ApiResponse.ok(Dict.create().set("total", all.getTotal()).set("data", all.getList())));}}演示示例
啟動項目,輸入http://localhost:8080/demo/job.html,進入管理界面,如圖所示:
點擊添加按鈕,添加測試任務(每秒執行一次)
添加完成后,查看后臺日志,成功執行相關任務,其他操作類似,這里就不一一列舉了
五、Quartz 監聽器
Quartz的監聽器用于當任務調度中你所關注事件發生時,能夠及時獲取這一事件的通知。類似于任務執行過程中的郵件、短信類的提醒
Quartz監聽器主要有JobListener、TriggerListener、SchedulerListener三種,分別表示任務、觸發器、調度器對應的監聽器
1.JobListener
任務調度中,與任務 Job 相關的事件包括: Job 開始要執行的提示,執行完成的提示,接口如下:
public interface JobListener {String getName();void jobToBeExecuted(JobExecutionContext context);void jobExecutionVetoed(JobExecutionContext context);void jobWasExecuted(JobExecutionContext context,JobExecutionException jobException); }方法說明
-
getName():用于獲取改JobListener 的名稱
-
jobToBeExecuted():Scheduler 在 JobDetail 將要被執行時調用這個方法
-
jobExecutionVetoed():Scheduler 在 JobDetail 即將被執行,但又被 TriggerListener 否決時會調用該方法
-
jobWasExecuted():Scheduler 在 JobDetail 被執行之后調用這個方法
代碼示例
Job 任務類
@Slf4j @PersistJobDataAfterExecution public class TestJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext){System.out.println("TestJob 執行啦");} }JobListener
public class MyJobListener implements JobListener {@Overridepublic String getName() {String name = getClass().getSimpleName();System.out.println("監聽器的名稱是:" + name);return name;}@Overridepublic void jobToBeExecuted(JobExecutionContext context) {String jobName = context.getJobDetail().getKey().getName();System.out.println("Job的名稱是:" + jobName + "\tScheduler在JobDetail將要被執行時調用這個方法");}@Overridepublic void jobExecutionVetoed(JobExecutionContext context) {String jobName = context.getJobDetail().getKey().getName();System.out.println("Job的名稱是:" + jobName + "\tScheduler在JobDetail即將被執行,但又被TriggerListerner否決時會調用該方法");}@Overridepublic void jobWasExecuted(JobExecutionContext context, JobExecutionException jobException) {String jobName = context.getJobDetail().getKey().getName();System.out.println("Job的名稱是:" + jobName + "\tScheduler在JobDetail被執行之后調用這個方法");} }任務調度類
@Slf4j public class TestScheduler {public static void main(String[] args) throws Exception {// 獲取任務調度的實例Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// 定義任務調度實例, 并與TestJob綁定JobDetail jobDetail = JobBuilder.newJob(TestJob.class).usingJobData("executeCount", 0).withIdentity("testJob", "testJobGroup").build();// 定義觸發器, 會馬上執行一次, 接著5秒執行一次Trigger trigger = TriggerBuilder.newTrigger().usingJobData("testInfo", "trigger數據存放").withIdentity("testTrigger", "testTriggerGroup").startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build();// 創建并注冊一個全局的Job Listenerscheduler.getListenerManager().addJobListener(new MyJobListener(),EverythingMatcher.allJobs());// 使用觸發器調度任務的執行scheduler.scheduleJob(jobDetail, trigger);// 開啟任務scheduler.start();} } /** OUTPUT: 監聽器的名稱是:MyJobListener Job的名稱是:testJob Scheduler在JobDetail將要被執行時調用這個方法 TestJob 執行啦 監聽器的名稱是:MyJobListener Job的名稱是:testJob Scheduler在JobDetail被執行之后調用這個方法 **/2. TriggerListener
任務調度中,與觸發器 Trigger 相關的事件包括: 觸發器觸發、觸發器未正常觸發、觸發器完成等
public interface TriggerListener {public String getName();public void triggerFired(Trigger trigger, JobExecutionContext context);public boolean vetoJobExecution(Trigger trigger, JobExecutionContext context);public void triggerMisfired(Trigger trigger);public void triggerComplete(Trigger trigger, JobExecutionContext context, int triggerInstructionCode); }方法說明
-
getName():用于獲取觸發器的名稱
-
triggerFired():當與監聽器相關聯的Trigger被觸發,Job上的execute()方法將被執行時,Scheduler就調用該方法。
-
vetoJobExecution():在 Trigger 觸發后,Job 將要被執行時由 Scheduler 調用這個方法。TriggerListener 給了一個選擇去否決 Job 的執行。假如這個方法返回 true,這個 Job 將不會為此次 Trigger 觸發而得到執行。
-
triggerMisfired():Scheduler 調用這個方法是在 Trigger 錯過觸發時。你應該關注此方法中持續時間長的邏輯:在出現許多錯過觸發的 Trigger 時,長邏輯會導致骨牌效應。你應當保持這上方法盡量的小。
-
triggerComplete():Trigger 被觸發并且完成了 Job 的執行時,Scheduler 調用這個方法。
代碼示例
Job 任務類
@Slf4j @PersistJobDataAfterExecution public class TestJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext){System.out.println("TestJob 執行啦");} }TriggerListener
public class MyTriggerListener implements TriggerListener {private String name;public MyTriggerListener(String name) {this.name = name;}@Overridepublic String getName() {return name;}@Overridepublic void triggerFired(Trigger trigger, JobExecutionContext context) {String triggerName = trigger.getKey().getName();System.out.println(triggerName + " 被觸發");}@Overridepublic boolean vetoJobExecution(Trigger trigger, JobExecutionContext context) {String triggerName = trigger.getKey().getName();System.out.println(triggerName + " 沒有被觸發");return false; // true:表示不會執行Job的方法}@Overridepublic void triggerMisfired(Trigger trigger) {String triggerName = trigger.getKey().getName();System.out.println(triggerName + " 錯過觸發");}@Overridepublic void triggerComplete(Trigger trigger, JobExecutionContext jobExecutionContext, Trigger.CompletedExecutionInstruction completedExecutionInstruction) {String triggerName = trigger.getKey().getName();System.out.println(triggerName + " 完成之后觸發");}}任務調度類
@Slf4j public class TestScheduler {public static void main(String[] args) throws Exception {// 獲取任務調度的實例Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// 定義任務調度實例, 并與TestJob綁定JobDetail jobDetail = JobBuilder.newJob(TestJob.class).usingJobData("executeCount", 0).withIdentity("testJob", "testJobGroup").build();// 定義觸發器, 會馬上執行一次, 接著5秒執行一次Trigger trigger = TriggerBuilder.newTrigger().usingJobData("testInfo", "trigger數據存放").withIdentity("testTrigger", "testTriggerGroup").startNow().withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build();// 創建并注冊一個全局的Trigger Listenerscheduler.getListenerManager().addTriggerListener(new MyTriggerListener("simpleTrigger"), EverythingMatcher.allTriggers());// 使用觸發器調度任務的執行scheduler.scheduleJob(jobDetail, trigger);// 開啟任務scheduler.start();} } /** OUTPUT: testTrigger 被觸發 testTrigger 沒有被觸發 TestJob 執行啦 testTrigger 完成之后觸發 **/2. SchedulerListener
SchedulerListener 會在Scheduler的生命周期中關鍵事件發生時被調用。與Scheduler有關的事件包括:增加一個job/trigger,刪除一個job/trigger,scheduler發生嚴重錯誤,關閉scheduler等。
public interface SchedulerListener {public void jobScheduled(Trigger trigger);public void jobUnscheduled(String triggerName, String triggerGroup);public void triggerFinalized(Trigger trigger);public void triggersPaused(String triggerName, String triggerGroup);public void triggersResumed(String triggerName, String triggerGroup);public void jobsPaused(String jobName, String jobGroup);public void jobsResumed(String jobName, String jobGroup);public void schedulerError(String msg, SchedulerException cause);public void schedulerStarted();public void schedulerInStandbyMode();public void schedulerShutdown();public void schedulingDataCleared(); }方法說明
- jobScheduled():用于部署JobDetail時調用
- jobUnscheduled():用于卸載JobDetail時調用
- triggerFinalized():當一個 Trigger 來到了再也不會觸發的狀態時調用這個方法。除非這個 Job 已設置成了持久性,否則它就會從 Scheduler 中移除。
- triggersPaused():Scheduler 調用這個方法是發生在一個 Trigger 或 Trigger 組被暫停時。假如是 Trigger 組的話,triggerName 參數將為 null。
- triggersResumed():Scheduler 調用這個方法是發生成一個 Trigger 或 Trigger 組從暫停中恢復時。假如是 Trigger 組的話,假如是 Trigger 組的話,triggerName 參數將為 null。參數將為 null。
- jobsPaused():當一個或一組 JobDetail 暫停時調用這個方法。
- jobsResumed():當一個或一組 Job 從暫停上恢復時調用這個方法。假如是一個 Job 組,jobName 參數將為 null。
- schedulerError():在 Scheduler 的正常運行期間產生一個嚴重錯誤時調用這個方法。
- schedulerStarted():當Scheduler 開啟時,調用該方法
- schedulerInStandbyMode(): 當Scheduler處于StandBy模式時,調用該方法
- schedulerShutdown():當Scheduler停止時,調用該方法
- schedulingDataCleared():當Scheduler中的數據被清除時,調用該方法。
代碼示例
Job 任務類
@Slf4j @PersistJobDataAfterExecution public class TestJob implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext){System.out.println("TestJob 執行啦");} }SchedulerListener
public class MySchedulerListener implements SchedulerListener {@Overridepublic void jobScheduled(Trigger trigger) {String jobName = trigger.getJobKey().getName();System.out.println(jobName + " 完成部署");}@Overridepublic void jobUnscheduled(TriggerKey triggerKey) {System.out.println(triggerKey + " 完成卸載");}@Overridepublic void triggerFinalized(Trigger trigger) {System.out.println("觸發器被移除 " + trigger.getJobKey().getName());}@Overridepublic void triggerPaused(TriggerKey triggerKey) {System.out.println(triggerKey + " 正在被暫停");}@Overridepublic void triggersPaused(String triggerGroup) {System.out.println("觸發器組 " + triggerGroup + " 正在被暫停");}@Overridepublic void triggerResumed(TriggerKey triggerKey) {System.out.println(triggerKey + " 正在從暫停中恢復");}@Overridepublic void triggersResumed(String triggerGroup) {System.out.println("觸發器組 " + triggerGroup + " 正在從暫停中恢復");}@Overridepublic void jobAdded(JobDetail jobDetail) {System.out.println(jobDetail.getKey() + " 添加工作任務");}@Overridepublic void jobDeleted(JobKey jobKey) {System.out.println(jobKey + " 刪除工作任務");}@Overridepublic void jobPaused(JobKey jobKey) {System.out.println(jobKey + " 工作任務正在被暫停");}@Overridepublic void jobsPaused(String jobGroup) {System.out.println("工作任務組 " + jobGroup + " 正在被暫停");}@Overridepublic void jobResumed(JobKey jobKey) {System.out.println(jobKey + " 正在從暫停中恢復");}@Overridepublic void jobsResumed(String jobGroup) {System.out.println("工作任務組 " + jobGroup + " 正在從暫停中恢復");}@Overridepublic void schedulerError(String msg, SchedulerException cause) {System.out.println("產生嚴重錯誤時調用: " + msg + " " + cause.getUnderlyingException());}@Overridepublic void schedulerInStandbyMode() {System.out.println("調度器在掛起模式下調用");}@Overridepublic void schedulerStarted() {System.out.println("調度器 開啟時調用");}@Overridepublic void schedulerStarting() {System.out.println("調度器 正在開啟時調用");}@Overridepublic void schedulerShutdown() {System.out.println("調度器 已經被關閉 時調用");}@Overridepublic void schedulerShuttingdown() {System.out.println("調度器 正在被關閉 時調用");}@Overridepublic void schedulingDataCleared() {System.out.println("調度器的數據被清除時調用");} }任務調度類
@Slf4j public class TestScheduler {public static void main(String[] args) throws Exception {// 獲取任務調度的實例Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();// 定義任務調度實例, 并與TestJob綁定JobDetail jobDetail = JobBuilder.newJob(TestJob.class).usingJobData("executeCount", 0).withIdentity("testJob", "testJobGroup").build();// 定義觸發器, 會馬上執行一次, 接著5秒執行一次Date endTime = new Date();endTime.setTime(endTime.getTime()+5000);Trigger trigger = TriggerBuilder.newTrigger().usingJobData("testInfo", "trigger數據存放").withIdentity("testTrigger", "testTriggerGroup").startNow().endAt(endTime) //設置了停止時間.withSchedule(SimpleScheduleBuilder.repeatSecondlyForever(5)).build();// 創建SchedulerListenerscheduler.getListenerManager().addSchedulerListener(new MySchedulerListener());// 使用觸發器調度任務的執行scheduler.scheduleJob(jobDetail, trigger);// 開啟任務scheduler.start();} } /** OUTPUT: testJobGroup.testJob 添加工作任務 testJob 完成部署 調度器 正在開啟時調用 調度器 開啟時調用 TestJob 執行啦 觸發器被移除 testJob testJobGroup.testJob 刪除工作任務 **/總結
以上就是今天要講的內容,本文僅僅簡單介紹了quartz的入門案例,實現動態管理定時任務,以上方法親測有效,希望能給大家一個參考。
創作不易,關注💖、點贊👍、收藏🎉就是對作者最大的鼓勵👏,歡迎在下方評論留言🧐
總結
以上是生活随笔為你收集整理的Quartz 快速入门案例,看这一篇就够了的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 响铃:百度图腾要做正版授权平台,它能解决
- 下一篇: alma linux 8.6显示桌面图标