在Spring Boot 中使用定时框架Quartz,触发时间在数据库表中获取
背景:在前端页面新建定时任务,将任务存入数据库,包含触发时间及触发模式
数据库表触发时间字段如下:
一、Quartz的介绍
Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目,是完全由java开发的一个开源的任务日程管理系统,“任务进度管理器”就是一个在预先确定(被纳入日程)的时间到达时,负责执行(或者通知)其他软件组件的系统。
Quartz用一个小Java库发布文件(.jar文件),这个库文件包含了所有Quartz核心功能。这些功能的主要接口(API)是Scheduler接口。它提供了简单的操作,例如:将任务纳入日程或者从日程中取消,开始/停止/暂停日程进度。
不了解Quartz的可以查看下面的相关文章:
https://www.cnblogs.com/wangjiming/p/10027439.html
二、将Quartz引入Spring Boot以及使用
1、导入依赖的jar包:
org.springframework.boot spring-boot-starter-quartz
版本直接由spring boot控制
2、新建一个任务类,并实现Job接口,此接口只有一个方法void execute(JobExecutionContext jobExecutionContext)
public class MyJob implements Job { private static IDutyService dutyService; static { dutyService = SpringUtil.getBean(IDutyService.class); } @Override public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException { DutyDefEntity dutyDef = (DutyDefEntity) jobExecutionContext.getJobDetail().getJobDataMap().get("dutyDef");// 获取定义任务数据 Boolean success = this.dutyService.saveDuty(dutyDef);// 实现发布任务的业务接口 if (success) { System.out.println("发布例行任务成功"); } }}
3、接下来新建一个工厂类,创建定时任务
@Service@Componentpublic class MySchedulerFactory { @Autowired SchedulerFactoryBean schedulerFactoryBean; // 获取scheduler private Scheduler getScheduler(){ return schedulerFactoryBean.getScheduler(); } // 项目启动 开启任务 public void startJob(DutyDefEntity dutyDefEntity) throws SchedulerException, ClassNotFoundException { Scheduler scheduler = getScheduler(); // 获取scheduler JobKey jobKey = JobKey.jobKey(Func.toStr(dutyDefEntity.getId()), "group1");//根据唯一标识符获取任务 Class clazz = (Class) Class.forName("org.springblade.modules.time.MyJob"); JobDetail jobDetail1 = scheduler.getJobDetail(jobKey); String cron = ""; // 发布模式:隔天interval,指定日期specify if (dutyDefEntity.getAutoMode().equals("interval")) {// 隔天interval String[] time = dutyDefEntity.getAutoTime().toString().split(":");// 时分秒(数据库存的是时分秒) // 如:每隔2天,在12点34分发布 // cron = "0 34 12 */2" cron = "0 " + time[1] + " " + time[0] + " */" + dutyDefEntity.getAutoInterval(); } if (dutyDefEntity.getAutoMode().equals("specify")) {// 指定日期specify String[] time = dutyDefEntity.getAutoTime().toString().split(":");// 时分秒 // dutyDefEntity.getAutoMouth() 多个月份必须以英文逗号隔开 // 如:在4月和6月的23号,12点34分发布 // cron = "0 34 12 23 4,6 ? *" cron = "0 " + time[1] + " " + time[0] + " " + dutyDefEntity.getAutoDay() + " " + dutyDefEntity.getAutoMouth() + " ? *"; } if (jobDetail1==null){// 不存在就新建定时任务 JobDetail jobDetail = JobBuilder.newJob(clazz) .withIdentity(Func.toStr(dutyDefEntity.getId()), "group1").build(); jobDetail.getJobDataMap().put("dutyDef", dutyDefEntity);// 将要发布的任务传递到任务的实现类MyJob中 CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cron); CronTrigger cronTrigger = TriggerBuilder.newTrigger().withIdentity(Func.toStr(dutyDefEntity.getId()), "group1") .withSchedule(scheduleBuilder).build(); scheduler.scheduleJob(jobDetail, cronTrigger); }else {// 存在就修改触发时间 TriggerKey triggerKey = new TriggerKey(Func.toStr(dutyDefEntity.getId()), "group1"); CronTrigger cronTrigger = (CronTrigger) scheduler.getTrigger(triggerKey); String oldTime = cronTrigger.getCronExpression(); if (!oldTime.equalsIgnoreCase(cron)) { CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(cron); CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(Func.toStr(dutyDefEntity.getId()), "group1") .withSchedule(cronScheduleBuilder).build(); scheduler.rescheduleJob(triggerKey, trigger); } } }}
JobDetail是任务的定义,而Job是任务的执行逻辑。在JobDetail里会引用一个Job Class定义。每一个JobDetail都会有一个JobDataMap。JobDataMap本质就是一个Map的扩展类,只是提供了一些更便捷的方法,比如getString()之类的。
4、新建监听器类
@Configurationpublic class StartSchedulerListener implements ApplicationListener { @Autowired public MySchedulerFactory mySchedulerFactory; // springboot 启动监听 @Override public void onApplicationEvent(ContextRefreshedEvent event) { } //注入SchedulerFactoryBean @Bean public SchedulerFactoryBean schedulerFactoryBean() { SchedulerFactoryBean schedulerFactoryBean = new SchedulerFactoryBean(); return schedulerFactoryBean; }}
其实可以不用建立这个类,可以将SchedulerFactoryBean直接在MySchedulerFactory 中注入bean,代码如下:
@Resourceprivite SchedulerFactoryBean schedulerFactoryBean;
OK,现在需要去调用startJob方法,执行定时任务
5、利用springboot自带的定时器,每隔10分钟从数据库中获取最新的数据,并启动定时任务
@Component@EnableSchedulingpublic class StartJob { @Resource private IDutyDefService dutyDefService; @Autowired public MySchedulerFactory mySchedulerFactory; /** * 启动定时器,10分钟执行一次,获取数据库最新数据 */ @Scheduled(initialDelay=1000, fixedDelay=600000) // 第一次延迟1秒执行,然后在上一次执行完毕时间点10分钟秒再次执行; public void startTaskTimerByTenMin() { try { // 获取例行任务定义 QueryWrapper wrapper = new QueryWrapper(); List list = dutyDefService.list(wrapper); if (Func.isNotEmpty(list)) { for (DutyDefEntity dutyDefEntity : list) { mySchedulerFactory.startJob(dutyDefEntity);// 开启定时任务,将要发布的任务传递进去 } } } catch (Exception e) { } }}
完成!!!!!