以前咱們講過一個分佈式任務調度框架PowerJob,能夠經過可視化的方式來進行任務調度。可是有時候咱們只是須要一個輕量級的任務調度功能,而PowerJob須要搭建調度中心未免有些重,這時候SpringBoot官方支持的任務調度框架Quartz就派上用場了!本文主要介紹Quartz在SpringBoot中的使用,讓你在實現任務調度上有更多的選擇!
SpringBoot實戰電商項目mall(40k+star)地址:https://github.com/macrozheng/malljava
Quartz是一款功能強大的開源任務調度框架,幾乎能夠集成到任何Java應用程序中(小到單機應用,大到分佈式應用)。Quartz可用於建立簡單或複雜的任務調度,用以執行數以萬計的任務。任務被定義爲標準化的Java組件,Java編寫的任務均可以被執行。mysql
Quartz中有一些比較核心的概念,理解它們對使用Quartz頗有幫助!
Cron表達式是一個字符串,包括6~7個時間元素,在Quartz中能夠用於指定任務的執行時間。
Seconds Minutes Hours DayofMonth Month DayofWeek
時間元素 | 可出現的字符 | 有效數值範圍 |
---|---|---|
Seconds | , - * / | 0-59 |
Minutes | , - * / | 0-59 |
Hours | , - * / | 0-23 |
DayofMonth | , - * / ? L W | 0-31 |
Month | , - * / | 1-12 |
DayofWeek | , - * / ? L # | 1-7或SUN-SAT |
字符 | 做用 | 舉例 |
---|---|---|
, | 列出枚舉值 | 在Minutes域使用5,10,表示在5分和10分各觸發一次 |
\- | 表示觸發範圍 | 在Minutes域使用5-10,表示從5分到10分鐘每分鐘觸發一次 |
\* | 匹配任意值 | 在Minutes域使用*, 表示每分鐘都會觸發一次 |
/ | 起始時間開始觸發,每隔固定時間觸發一次 | 在Minutes域使用5/10,表示5分時觸發一次,每10分鐘再觸發一次 |
? | 在DayofMonth和DayofWeek中,用於匹配任意值 | 在DayofMonth域使用?,表示天天都觸發一次 |
\# | 在DayofMonth中,肯定第幾個星期幾 | 1#3表示第三個星期日 |
L | 表示最後 | 在DayofWeek中使用5L,表示在最後一個星期四觸發 |
W | 表示有效工做日(週一到週五) | 在DayofMonth使用5W,若是5日是星期六,則將在最近的工做日4日觸發一次 |
其實CRON表達式無需多記,須要使用的時候直接使用在線生成器就能夠了,地址:https://cron.qqe2.com/git
接下來咱們講下如何在SpringBoot中使用Quartz來實現任務調度,在電商系統中每每會有須要定時發送郵件或者站內信的需求,咱們以此爲場景來實現下!
resources
目錄下,名稱爲tables_mysql.sql
,建立成功後數據庫中多出11張表;pom.xml
中添加Quartz的相關依賴便可,SpringBoot官方已經給咱們提供好了相關Starter;<!--SpringBoot集成QuartZ--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency>
application.yml
中添加Quartz相關配置,配置說明直接看註釋就行了,主要是對scheduler
、jobStore
和threadPool
進行配置;spring: quartz: job-store-type: jdbc # quartz任務存儲類型:jdbc或memory wait-for-jobs-to-complete-on-shutdown: true # 關閉時等待任務完成 overwrite-existing-jobs: true # 能夠覆蓋已有的任務 properties: # quartz原生配置 org: quartz: scheduler: instanceName: scheduler # 調度器實例名稱 instanceId: AUTO # 調度器實例ID自動生成 jobStore: class: org.quartz.impl.jdbcjobstore.JobStoreTX # 調度信息存儲處理類 driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate # 使用徹底兼容JDBC的驅動 tablePrefix: QRTZ_ # quartz相關表前綴 useProperties: false # 是否將JobDataMap中的屬性轉爲字符串存儲 threadPool: class: org.quartz.simpl.SimpleThreadPool # 指定線程池實現類,對調度器提供固定大小的線程池 threadCount: 10 # 設置併發線程數量 threadPriority: 5 # 指定線程優先級
/** * Quartz定時任務操做類 * Created by macro on 2020/9/27. */ public interface ScheduleService { /** * 經過CRON表達式調度任務 */ String scheduleJob(Class<? extends Job> jobBeanClass, String cron, String data); /** * 調度指定時間的任務 */ String scheduleFixTimeJob(Class<? extends Job> jobBeanClass, Date startTime, String data); /** * 取消定時任務 */ Boolean cancelScheduleJob(String jobName); }
Scheduler
、CronTrigger
、JobDetail
的API實現相關方法;/** * Quartz定時任務操做實現類 * Created by macro on 2020/9/27. */ @Slf4j @Service public class ScheduleServiceImpl implements ScheduleService { @Autowired private Scheduler scheduler; private String defaultGroup = "default_group"; @Override public String scheduleJob(Class<? extends Job> jobBeanClass, String cron, String data) { // 建立須要執行的任務 String jobName = UUID.fastUUID().toString(); JobDetail jobDetail = JobBuilder.newJob(jobBeanClass) .withIdentity(jobName, defaultGroup) .usingJobData("data", data) .build(); //建立觸發器,指定任務執行時間 CronTrigger cronTrigger = TriggerBuilder.newTrigger() .withIdentity(jobName, defaultGroup) .withSchedule(CronScheduleBuilder.cronSchedule(cron)) .build(); //使用調度器進行任務調度 try { scheduler.scheduleJob(jobDetail, cronTrigger); } catch (SchedulerException e) { e.printStackTrace(); log.info("建立定時任務失敗!"); } return jobName; } @Override public String scheduleFixTimeJob(Class<? extends Job> jobBeanClass, Date startTime, String data) { //日期轉CRON表達式 String startCron = String.format("%d %d %d %d %d ? %d", DateUtil.second(startTime), DateUtil.minute(startTime), DateUtil.hour(startTime, true), DateUtil.dayOfMonth(startTime), DateUtil.month(startTime) + 1, DateUtil.year(startTime)); return scheduleJob(jobBeanClass, startCron, data); } @Override public Boolean cancelScheduleJob(String jobName) { boolean success = false; try { // 暫停觸發器 scheduler.pauseTrigger(new TriggerKey(jobName, defaultGroup)); // 移除觸發器中的任務 scheduler.unscheduleJob(new TriggerKey(jobName, defaultGroup)); // 刪除任務 scheduler.deleteJob(new JobKey(jobName, defaultGroup)); success = true; } catch (SchedulerException e) { e.printStackTrace(); } return success; } }
QuartzJobBean
類,實現executeInternal
方法便可,這裏定義了三個任務,定時發送郵件、定時發送站內信和執行CRON表達式任務;/** * 發送郵件定時任務執行器 * Created by macro on 2020/9/27. */ @Slf4j @Component public class SendEmailJob extends QuartzJobBean { @Autowired private ScheduleService scheduleService; @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { Trigger trigger = jobExecutionContext.getTrigger(); JobDetail jobDetail = jobExecutionContext.getJobDetail(); JobDataMap jobDataMap = jobDetail.getJobDataMap(); String data = jobDataMap.getString("data"); log.info("定時發送郵件操做:{}",data); //完成後刪除觸發器和任務 scheduleService.cancelScheduleJob(trigger.getKey().getName()); } }
/** * 發送站內信定時任務執行器 * Created by macro on 2020/9/27. */ @Slf4j @Component public class SendMessageJob extends QuartzJobBean { @Autowired private ScheduleService scheduleService; @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { Trigger trigger = jobExecutionContext.getTrigger(); JobDetail jobDetail = jobExecutionContext.getJobDetail(); JobDataMap jobDataMap = jobDetail.getJobDataMap(); String data = jobDataMap.getString("data"); log.info("定時發送站內信操做:{}",data); //完成後刪除觸發器和任務 scheduleService.cancelScheduleJob(trigger.getKey().getName()); } }
/** * 使用CRON表達式的任務執行器 * Created by macro on 2020/9/29. */ @Slf4j @Component public class CronProcessJob extends QuartzJobBean { @Override protected void executeInternal(JobExecutionContext jobExecutionContext) throws JobExecutionException { JobDetail jobDetail = jobExecutionContext.getJobDetail(); JobDataMap jobDataMap = jobDetail.getJobDataMap(); String data = jobDataMap.getString("data"); log.info("CRON表達式任務執行:{}",data); } }
/** * 定時任務調度相關接口 * Created by macro on 2020/9/29. */ @Api(tags = "ScheduleController", description = "定時任務調度相關接口") @RestController @RequestMapping("/schedule") public class ScheduleController { @Autowired private ScheduleService scheduleService; @ApiOperation("定時發送郵件") @PostMapping("/sendEmail") public CommonResult sendEmail(@RequestParam String startTime,@RequestParam String data) { Date date = DateUtil.parse(startTime, DatePattern.NORM_DATETIME_FORMAT); String jobName = scheduleService.scheduleFixTimeJob(SendEmailJob.class, date, data); return CommonResult.success(jobName); } @ApiOperation("定時發送站內信") @PostMapping("/sendMessage") public CommonResult sendMessage(@RequestParam String startTime,@RequestParam String data) { Date date = DateUtil.parse(startTime, DatePattern.NORM_DATETIME_FORMAT); String jobName = scheduleService.scheduleFixTimeJob(SendMessageJob.class, date, data); return CommonResult.success(jobName); } @ApiOperation("經過CRON表達式調度任務") @PostMapping("/scheduleJob") public CommonResult scheduleJob(@RequestParam String cron, @RequestParam String data) { String jobName = scheduleService.scheduleJob(CronProcessJob.class, cron, data); return CommonResult.success(jobName); } @ApiOperation("取消定時任務") @PostMapping("/cancelScheduleJob") public CommonResult cancelScheduleJob(@RequestParam String jobName) { Boolean success = scheduleService.cancelScheduleJob(jobName); return CommonResult.success(success); } }
2020-09-30 11:23:00.035 INFO 10160 --- [eduler_Worker-1] com.macro.mall.tiny.job.SendEmailJob : 定時發送郵件操做:發送郵件內容
2020-09-30 11:26:30.024 INFO 10160 --- [eduler_Worker-2] com.macro.mall.tiny.job.CronProcessJob : CRON表達式任務執行:CRON消息內容 2020-09-30 11:26:40.025 INFO 10160 --- [eduler_Worker-3] com.macro.mall.tiny.job.CronProcessJob : CRON表達式任務執行:CRON消息內容 2020-09-30 11:26:50.017 INFO 10160 --- [eduler_Worker-4] com.macro.mall.tiny.job.CronProcessJob : CRON表達式任務執行:CRON消息內容 2020-09-30 11:27:00.023 INFO 10160 --- [eduler_Worker-5] com.macro.mall.tiny.job.CronProcessJob : CRON表達式任務執行:CRON消息內容 2020-09-30 11:27:10.019 INFO 10160 --- [eduler_Worker-6] com.macro.mall.tiny.job.CronProcessJob : CRON表達式任務執行:CRON消息內容
jobName
,調用取消定時任務的接口來取消任務,調用成功後定時任務不在執行。官方文檔:http://www.quartz-scheduler.o...github
https://github.com/macrozheng...spring
本文 GitHub https://github.com/macrozheng/mall-learning 已經收錄,歡迎你們Star!