之前咱们讲过一个分布式任务调度框架PowerJob,能够通过可视化的形式来进行任务调度。然而有时候咱们只是须要一个轻量级的任务调度性能,而PowerJob须要搭建调度核心未免有些重,这时候SpringBoot官网反对的任务调度框架Quartz就派上用场了!本文次要介绍Quartz在SpringBoot中的应用,让你在实现任务调度上有更多的抉择!
SpringBoot实战电商我的项目mall(40k+star)地址:https://github.com/macrozheng/mall
Quartz简介
Quartz是一款功能强大的开源任务调度框架,简直能够集成到任何Java应用程序中(小到单机利用,大到分布式应用)。Quartz可用于创立简略或简单的任务调度,用以执行数以万计的工作。工作被定义为标准化的Java组件,Java编写的工作都能够被执行。
外围概念
Quartz中有一些比拟外围的概念,了解它们对应用Quartz很有帮忙!
- Scheduler(调度器):Quartz中的任务调度器,通过Trigger和JobDetail能够用来调度、暂停和删除工作。
- Trigger(触发器):Quartz中的触发器,能够通过CRON表达式来指定工作执行的工夫,工夫到了会主动触发工作执行。
- JobDetail(工作详情):Quartz中须要执行的工作详情,包含了工作的惟一标识和具体要执行的工作,能够通过JobDataMap往工作中传递数据。
- Job(工作):Quartz中具体的工作,蕴含了执行工作的具体方法。
CRON表达式
Cron表达式是一个字符串,包含6~7个工夫元素,在Quartz中能够用于指定工作的执行工夫。
CRON的语法格局
Seconds Minutes Hours DayofMonth Month DayofWeek
CRON格局中每个工夫元素的阐明
工夫元素 | 可呈现的字符 | 无效数值范畴 |
---|---|---|
Seconds | , - * / | 0-59 |
Minutes | , - * / | 0-59 |
Hours | , - * / | 0-23 |
DayofMonth | , - * / ? L W | 0-31 |
Month | , - * / | 1-12 |
DayofWeek | , - * / ? L # | 1-7或SUN-SAT |
CRON格局中特殊字符阐明
字符 | 作用 | 举例 |
---|---|---|
, | 列出枚举值 | 在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表达式生成器
其实CRON表达式无需多记,须要应用的时候间接应用在线生成器就能够了,地址:https://cron.qqe2.com/
整合SpringBoot应用
接下来咱们讲下如何在SpringBoot中应用Quartz来实现任务调度,在电商零碎中往往会有须要定时发送邮件或者站内信的需要,咱们以此为场景来实现下!
- Quartz存储工作信息有两种形式,应用内存或者应用数据库来存储,这里咱们采纳数据库存储的形式,首先须要新建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 # 指定线程优先级
- 创立任务调度业务接口,定义好三个办法,别离为通过CRON表达式调度工作、调度指定工夫的工作和勾销定时工作;
/** * 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@Servicepublic 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@Componentpublic 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@Componentpublic 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@Componentpublic 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 : 定时发送邮件操作:发送邮件内容
- 应用CRON表达式来启动一个定时工作,从0s开始,每隔10s执行一次;
- 控制台每隔10s打印工作执行信息;
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...
我的项目源码地址
https://github.com/macrozheng...
本文 GitHub https://github.com/macrozheng/mall-learning 曾经收录,欢送大家Star!