-
更多相关内容
-
springboot集成quartz
2021-12-12 00:09:13springboot集成quartz Spring Boot 集成 Quartz 定时任务,并实现对定时任务的管理,包括新增定时任务,删除定时任务,暂停定时任务,恢复定时任务,修改定时任务启动时间,以及定时任务列表查询。 代码地址:...springboot集成quartz
Spring Boot 集成 Quartz 定时任务,并实现对定时任务的管理,包括新增定时任务,删除定时任务,暂停定时任务,恢复定时任务,修改定时任务启动时间,以及定时任务列表查询。
代码地址:https://github.com/DNYDYS/spring-boot-quartz.git
后端
初始化
在
init/dbTables
下选择 Quartz 需要的表结构,然后手动创建表。pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <artifactId>spring-boot-demo-task-quartz</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging> <name>spring-boot-demo-task-quartz</name> <description>Demo project for Spring Boot</description> <parent> <groupId>com.dnydys</groupId> <artifactId>spring-boot-demo</artifactId> <version>1.0.0-SNAPSHOT</version> </parent> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <java.version>1.8</java.version> <mybatis.mapper.version>2.1.0</mybatis.mapper.version> <mybatis.pagehelper.version>1.2.10</mybatis.pagehelper.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <dependency> <groupId>tk.mybatis</groupId> <artifactId>mapper-spring-boot-starter</artifactId> <version>${mybatis.mapper.version}</version> </dependency> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper-spring-boot-starter</artifactId> <version>${mybatis.pagehelper.version}</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-all</artifactId> </dependency> <dependency> <groupId>com.google.guava</groupId> <artifactId>guava</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> </dependencies> <build> <finalName>spring-boot-demo-task-quartz</finalName> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
application.yml
server: port: 9080 servlet: context-path: /demo spring: # 省略其余配置,具体请 clone 本项目,查看详情 # ...... quartz: # 参见 org.springframework.boot.autoconfigure.quartz.QuartzProperties job-store-type: jdbc wait-for-jobs-to-complete-on-shutdown: true scheduler-name: SpringBootDemoScheduler properties: org.quartz.threadPool.threadCount: 5 org.quartz.threadPool.threadPriority: 5 org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread: true org.quartz.jobStore.misfireThreshold: 5000 org.quartz.jobStore.class: org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegate # 在调度流程的第一步,也就是拉取待即将触发的triggers时,是上锁的状态,即不会同时存在多个线程拉取到相同的trigger的情况,也就避免的重复调度的危险。参考:https://segmentfault.com/a/1190000015492260 org.quartz.jobStore.acquireTriggersWithinLock: true # ......
前端
<div id="job"> <div id="top"> <el-button size="small" type="primary" plain @click="search" :loading="loading" icon="el-icon-search">查询 </el-button> <el-button size="small" type="primary" plain @click="handleadd" icon="el-icon-plus">添加</el-button> </div> <br/> <div> <el-table ref="jobTable" :data="tableData" style="width:100%" border center> <el-table-column prop="jobName" label="任务名称" show-overflow-tooltip align="center"></el-table-column> <el-table-column prop="jobGroup" label="任务所在组" sortable align="center"></el-table-column> <el-table-column prop="jobClassName" label="任务类名" align="center"></el-table-column> <el-table-column prop="triggerName" label="触发器名称" align="center"></el-table-column> <el-table-column prop="triggerGroup" label="触发器所在组" sortable align="center"></el-table-column> <el-table-column prop="cronExpression" label="表达式" align="center"></el-table-column> <el-table-column prop="timeZoneId" label="时区" align="center"></el-table-column> <el-table-column prop="triggerState" label="状态" align="center" :formatter="formatState"></el-table-column> <el-table-column label="操作" width="300" align="center"> <template scope="scope"> <el-button size="small" type="warning" @click="handlePause(scope.$index, scope.row)"> 暂停 </el-button> <el-button size="small" type="info" @click="handleResume(scope.$index, scope.row)"> 恢复 </el-button> <el-button size="small" type="danger" @click="handleDelete(scope.$index, scope.row)"> 删除 </el-button> <el-button size="small" type="success" @click="handleUpdate(scope.$index, scope.row)"> 修改 </el-button> </template> </el-table-column> </el-table> <div align="center"> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage" :page-sizes="[10, 20, 30, 40]" :page-size="pagesize" layout="total, sizes, prev, pager, next, jumper" :total="totalCount"> </el-pagination> </div> </div> <el-dialog title="添加任务" :visible.sync="dialogFormVisible"> <el-form :model="form"> <el-form-item label="任务名称" label-width="100px" style="width:90%"> <el-input v-model="form.jobName" auto-complete="off"></el-input> </el-form-item> <el-form-item label="任务分组" label-width="100px" style="width:90%"> <el-input v-model="form.jobGroup" auto-complete="off"></el-input> </el-form-item> <el-form-item label="表达式" label-width="100px" style="width:90%"> <el-input v-model="form.cronExpression" auto-complete="off"></el-input> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click="dialogFormVisible = false">取 消</el-button> <el-button type="primary" @click="add">确 定</el-button> </div> </el-dialog> <el-dialog title="修改任务" :visible.sync="updateFormVisible"> <el-form :model="updateform"> <el-form-item label="表达式" label-width="100px" style="width:90%"> <el-input v-model="updateform.cronExpression" auto-complete="off"></el-input> </el-form-item> </el-form> <div slot="footer" class="dialog-footer"> <el-button @click="updateFormVisible = false">取 消</el-button> <el-button type="primary" @click="update">确 定</el-button> </div> </el-dialog> </div>
启动
- clone 本项目
- 初始化表格
- 启动
SpringBootDemoTaskQuartzApplication.java
- 打开浏览器,查看 http://localhost:9080/demo/job.html
com.xkcoding.task.quartz.job.HelloJob
HelloJob
*/6 * * * * ?
参考
-
Spring Boot 官方文档:https://docs.spring.io/spring-boot/docs/2.1.0.RELEASE/reference/htmlsingle/#boot-features-quartz
-
Quartz 官方文档:http://www.quartz-scheduler.org/documentation/quartz-2.2.x/quick-start.html
-
Quartz 重复调度问题:https://segmentfault.com/a/1190000015492260
-
关于Quartz定时任务状态 (在
QRTZ_TRIGGERS
表中的TRIGGER_STATE
字段) -
Vue.js 官方文档:https://cn.vuejs.org/v2/guide/
-
Element-UI 官方文档:http://element-cn.eleme.io/#/zh-CN

-
SpringBoot集成Quartz分布式定时任务
2018-11-01 18:27:30SpringBoot集成Quartz完全分布式定时任务,即插即用,不好用直接捶我! SpringBoot集成Quartz分布式定时任务 SpringBoot集成Quartz分布式定时任务 -
Springboot集成quartz集群
2018-09-29 16:39:28本文章是关于springboot集成quartz集群的步骤,LZ亲测。 -
springboot 集成 quartz 集群 加 sql 等
2019-03-13 19:19:56springboot 集成 quartz 集群 加 sql 等 文章介绍 单机加集群都有 https://blog.csdn.net/weixin_42749765/article/details/88532413 -
Springboot集成Quartz
2021-12-16 20:04:51Quartz 是一个完全由 Java 编写的开源作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的...创建一个简单的SpringBoot项目,pom如下: <?xml version="1.0" encoding="UTF-8"?> <project xm.Quartz 是一个完全由 Java 编写的开源作业调度框架,为在 Java 应用程序中进行作业调度提供了简单却强大的机制。该文章不过多介绍Quartz的概念,主要做一个封装的记录。
功能点
- 添加CRON、固定间隔定时
- 修改定时的触发器
- 修改定时参数
- 暂停定时
- 启动暂停的定时
- 获取所有定时
- 启动所有定时
- 停止定时
0. 创建项目
创建一个简单的SpringBoot项目,pom如下:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.6.1</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>org.demo</groupId> <artifactId>quartz</artifactId> <version>0.0.1-SNAPSHOT</version> <name>quartz</name> <description>Demo project for Spring Boot</description> <properties> <java.version>11</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-quartz</artifactId> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
1. 定时类型
Quartz可以通过
org.quartz.Trigger.class
去拓展定时类型的,目前需求需要支持CRON和固定间隔两种定时类型,后期需要支持跳过节假日、周一~周五、周末等需求,所以需要让定时类型支持拓展。1.1定时类型
package org.demo.quartz.mode; /** * @author Xiaohan.Yuan * @version 1.0.0 * @ClassName TimingTriggerType.java * @Description 定时类型触发器类型 * @createTime 2021年12月16日 */ public enum TriggerType { CRON("标准CRON支持"), INTERVAL_MILLISECOND("固定间隔毫秒"), INTERVAL_SECOND("固定间隔秒"), INTERVAL_MINUTE("固定间隔分钟"), INTERVAL_HOUR("固定间隔小时"), WEEKDAYS("工作日,跳过节假日"), HOLIDAY("节假日") ; private String describe; TriggerType(String describe) { this.describe = describe; } }
1.2 构建定时任务的抽象类
我们需要构建不同的定时类型,不同的定时类型需要的参数也是不同的,因此我们需要抽象出定时的公用参数,将不同的参数多态实现。
package org.demo.quartz.mode; import lombok.Getter; import lombok.Setter; import org.demo.quartz.task.QuartzTaskJob; import java.util.Map; /** * @author Xiaohan.Yuan * @version 1.0.0 * @ClassName TimingModel.java * @Description 构建定时的model * @createTime 2021年12月16日 */ @Getter @Setter public class TimingModel { /** * 该定时的任务处理器 */ private Class<? extends QuartzTaskJob> taskClass; /** * 任务名 */ private String taskName; /** * 任务组名 * */ private String groupName; /** * 任务描述 * */ private String description; /** * 任务类型 */ private TriggerType type; /** * 任务参数,可在具体的QuartzTaskJob实现中获取这些参数 * */ private Map<String, Object> param; /** * 任务状态 * */ private String taskStatus; public TimingModel(Class<? extends QuartzTaskJob> taskClass, String taskName, String groupName, String description, TriggerType type, Map<String, Object> param) { this.taskClass = taskClass; this.taskName = taskName; this.groupName = groupName; this.description = description; this.type = type; this.param = param; } public TimingModel(Class<? extends QuartzTaskJob> taskClass, String taskName, String groupName, String description, TriggerType type) { this.taskClass = taskClass; this.taskName = taskName; this.groupName = groupName; this.description = description; this.type = type; } }
1.3 用以构建CRON定时任务
package org.demo.quartz.mode; import lombok.Getter; import lombok.Setter; import org.demo.quartz.task.QuartzTaskJob; import java.util.Map; /** * @author Xiaohan.Yuan * @version 1.0.0 * @ClassName CronTimingModel.java * @Description cron触发器model * @createTime 2021年12月16日 */ @Getter @Setter public class CronTimingModel extends TimingModel{ /** * cron表达式 * */ private String cronExpression; public CronTimingModel(Class<? extends QuartzTaskJob> taskClass, String taskName, String groupName, String description, Map<String, Object> param,String cronExpression) { super(taskClass, taskName, groupName, description, TriggerType.CRON, param); this.cronExpression = cronExpression; } public CronTimingModel(Class<? extends QuartzTaskJob> taskClass, String taskName, String groupName, String description,String cronExpression) { super(taskClass, taskName, groupName, description, TriggerType.CRON); this.cronExpression = cronExpression; } }
1.4 用以构建固定间隔定时任务
package org.demo.quartz.mode; import lombok.Getter; import lombok.Setter; import org.demo.quartz.exception.TimingException; import org.demo.quartz.task.QuartzTaskJob; import java.util.Map; /** * @author Xiaohan.Yuan * @version 1.0.0 * @ClassName IntervalTimingMode.java * @Description * @createTime 2021年12月16日 */ @Getter @Setter public class IntervalTimingMode extends TimingModel { /** * 事件间隔,根据TriggerType确定单位,除了数值为毫秒,该数值必须在-2^32~2^31 (-2147483648 ~ 2147483647) * */ private Long interval; /** * 重复次数,会执行该数值+1次,为空无限重复 * */ private Integer repeatCount; public IntervalTimingMode(Class<? extends QuartzTaskJob> taskClass, String taskName, String groupName, String description, TriggerType type, Map<String, Object> param, Long interval,Integer repeatCount) { super(taskClass, taskName, groupName, description, type, param); if (type != TriggerType.INTERVAL_MILLISECOND){ if (interval<(-2^32)||interval>(2^31)){ throw new TimingException("interval超出范围,除了类型为INTERVAL_MILLISECOND的数据间隔定时的interval范围必须在-2^32~2^31 (-2147483648 ~ 2147483647)"); } } this.interval = interval; this.repeatCount = repeatCount; } public IntervalTimingMode(Class<? extends QuartzTaskJob> taskClass, String taskName, String groupName, String description, TriggerType type, Long interval,Integer repeatCount) { super(taskClass, taskName, groupName, description, type); if (type != TriggerType.INTERVAL_MILLISECOND){ if (interval<(-2^32)||interval>(2^31)){ throw new TimingException("interval超出范围,除了类型为INTERVAL_MILLISECOND的数据间隔定时的interval范围必须在-2^32~2^31 (-2147483648 ~ 2147483647)"); } } this.interval = interval; this.repeatCount = repeatCount; } }
2.抽象任务类
package org.demo.quartz.task; import org.quartz.Job; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; /** * @author Xiaohan.Yuan * @version 1.0.0 * @ClassName QuartzTaskJob.java * @Description * @createTime 2021年12月16日 */ public interface QuartzTaskJob extends Job { @Override void execute(JobExecutionContext context) throws JobExecutionException; }
2.1 实现一个测试任务
package org.demo.quartz.task; import lombok.extern.slf4j.Slf4j; import org.quartz.JobDataMap; import org.quartz.JobExecutionContext; import org.quartz.JobExecutionException; import org.quartz.SimpleTrigger; import org.springframework.stereotype.Component; @Component @Slf4j public class TestQuartz implements QuartzTaskJob { @Override public void execute(JobExecutionContext context) throws JobExecutionException { // 获取参数 JobDataMap jobDataMap = context.getTrigger().getJobDataMap(); // 获取任务名 String name = context.getJobDetail().getJobBuilder().build().getKey().getName(); // 获取任务分组 String group = context.getJobDetail().getJobBuilder().build().getKey().getGroup(); // 获取任务描述 String description = context.getJobDetail().getDescription(); if (context.getTrigger() instanceof SimpleTrigger){ // 运行次数 System.out.println(((SimpleTrigger)context.getTrigger()).getTimesTriggered()); } log.info("----------------------" + "\n任务组:{}\n任务名:{}\n任务描述:{}\n获取参数paramKey:{}\n" + "----------------------" ,name,group,description,jobDataMap.getString("paramKey")); try { // QuartzJobManager.getInstance().jobdelete(this.getClass().getSimpleName(),"ah");//执行完此任务就删除自己 } catch (Exception e) { e.printStackTrace(); } } }
3. 构建触发器的不同实现
3.1 抽象触发器实现
package org.demo.quartz.trigger; import org.demo.quartz.mode.TriggerType; import org.demo.quartz.mode.TimingModel; import org.quartz.Trigger; /** * @author Xiaohan.Yuan * @version 1.0.0 * @ClassName TriggerHandler.java * @Description 触发器工厂 * @createTime 2021年12月16日 */ public interface ITriggerFactory { /** * 判断是否为该类型的触发器 * * @param triggerType 触发器类型 * @return boolean 如果是该类型的触发器返回true 否则返回false * @author YuanXiaohan * @date 2021/12/16 2:33 下午 */ public boolean check(TriggerType triggerType); public Trigger build(TimingModel timingModel); }
3.2 CRON触发器
package org.demo.quartz.trigger.factory; import org.demo.quartz.exception.TimingException; import org.demo.quartz.mode.CronTimingModel; import org.demo.quartz.mode.TriggerType; import org.demo.quartz.mode.TimingModel; import org.demo.quartz.trigger.ITriggerFactory; import org.quartz.CronScheduleBuilder; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.springframework.stereotype.Component; /** * @author Xiaohan.Yuan * @version 1.0.0 * @ClassName CronTrigger.java * @Description * @createTime 2021年12月16日 */ @Component public class CronTrigger implements ITriggerFactory { @Override public boolean check(TriggerType triggerType) { return triggerType==TriggerType.CRON; } @Override public Trigger build(TimingModel timingModel) { if (!(timingModel instanceof CronTimingModel)){ throw new TimingException("构建类型为CRON定时必须传入CronTimingModel.class的实现类"); } //按新的cronExpression表达式构建一个新的trigger CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(((CronTimingModel) timingModel).getCronExpression()); return TriggerBuilder.newTrigger().withIdentity(timingModel.getTaskName(), timingModel.getTaskName()) .withSchedule(scheduleBuilder).build(); } }
3.3 固定间隔触发器
package org.demo.quartz.trigger.factory; import org.demo.quartz.exception.TimingException; import org.demo.quartz.mode.IntervalTimingMode; import org.demo.quartz.mode.TimingModel; import org.demo.quartz.mode.TriggerType; import org.demo.quartz.trigger.ITriggerFactory; import org.quartz.SimpleScheduleBuilder; import org.quartz.Trigger; import org.quartz.TriggerBuilder; import org.springframework.stereotype.Component; /** * @author Xiaohan.Yuan * @version 1.0.0 * @ClassName IntervalTrigger.java * @Description * @createTime 2021年12月16日 */ @Component public class IntervalTrigger implements ITriggerFactory { @Override public boolean check(TriggerType triggerType) { return triggerType == TriggerType.INTERVAL_MINUTE || triggerType == TriggerType.INTERVAL_SECOND || triggerType == TriggerType.INTERVAL_MILLISECOND||triggerType == TriggerType.INTERVAL_HOUR; } @Override public Trigger build(TimingModel timingModel) { if (!(timingModel instanceof IntervalTimingMode)){ throw new TimingException("构建类型为INTERVAL定时必须传入IntervalTimingMode.class的实现类"); } //创建触发器 SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule(); Long interval = ((IntervalTimingMode) timingModel).getInterval(); Integer repeatCount = ((IntervalTimingMode) timingModel).getRepeatCount(); switch (timingModel.getType()){ case INTERVAL_MINUTE: simpleScheduleBuilder.withIntervalInMinutes(Math.toIntExact(interval)); break; case INTERVAL_HOUR: simpleScheduleBuilder.withIntervalInHours(Math.toIntExact(interval)); break; case INTERVAL_SECOND: simpleScheduleBuilder.withIntervalInSeconds(Math.toIntExact(interval)); break; case INTERVAL_MILLISECOND: simpleScheduleBuilder.withIntervalInMilliseconds(interval); break; } if (repeatCount==null){ // 无限重复 simpleScheduleBuilder.repeatForever(); }else { simpleScheduleBuilder.withRepeatCount(repeatCount); } return TriggerBuilder.newTrigger().withIdentity(timingModel.getTaskName(), timingModel.getTaskName()) .withSchedule(simpleScheduleBuilder).build(); } }
3.4 构建触发器工厂
package org.demo.quartz.trigger; import org.demo.quartz.mode.TimingModel; import org.quartz.Trigger; import org.springframework.stereotype.Component; import java.util.List; /** * @author Xiaohan.Yuan * @version 1.0.0 * @ClassName TriggerManager.java * @Description 触发器管理器, 用来生成触发器 * @createTime 2021年12月16日 */ @Component public class TriggerManager { private final List<ITriggerFactory> triggerFactories; public TriggerManager(List<ITriggerFactory> triggerFactories) { this.triggerFactories = triggerFactories; } /** * 生成对应的触发器 * * @param timingModel 触发器model * @return org.quartz.Trigger * @author YuanXiaohan * @date 2021/12/16 2:53 下午 */ public Trigger build(TimingModel timingModel) { for (ITriggerFactory triggerFactory : triggerFactories) { if (triggerFactory.check(timingModel.getType())) { return triggerFactory.build(timingModel); } } return null; } }
3. 构建定时管理类
该方法包含:
- 添加定时
- 更新定时触发器
- 更新任务参数
- 删除任务
- 暂停任务
- 将暂停的任务恢复执行
- 启动所有任务
- 关闭定时任务
- 获取所有任务
package org.demo.quartz; import lombok.extern.slf4j.Slf4j; import org.demo.quartz.mode.CronTimingModel; import org.demo.quartz.mode.TimingModel; import org.demo.quartz.trigger.TriggerManager; import org.demo.quartz.exception.TimingException; import org.quartz.*; import org.quartz.impl.matchers.GroupMatcher; import org.springframework.context.annotation.Configuration; import java.lang.reflect.InvocationTargetException; import java.util.*; /** * @author Xiaohan.Yuan * @version 1.0.0 * @ClassName QuartzTaskManager.java * @Description * @createTime 2021年12月16日 */ @Configuration @Slf4j public class QuartzTaskManager { private final Scheduler scheduler; private final Boolean initStatus; private final TriggerManager triggerManager; private static QuartzTaskManager taskManager; public QuartzTaskManager(Scheduler scheduler, TriggerManager triggerManager) { this.scheduler = scheduler; taskManager = this; boolean status = true; try { // 启动调度器 scheduler.start(); } catch (SchedulerException e) { log.error("定时器调度器启动失败,定时器不可用!", e); status = false; } initStatus = status; this.triggerManager = triggerManager; } public static QuartzTaskManager getInstance(){ return taskManager; } /** * 添加定时任务 * * @param timingModel 任务model * @author YuanXiaohan * @date 2021/12/16 3:09 下午 */ public void addTask(TimingModel timingModel) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, SchedulerException { checkTimingInit(); // 构建任务信息 JobDetail jobDetail = JobBuilder.newJob(timingModel.getTaskClass().getDeclaredConstructor().newInstance().getClass()) .withDescription(timingModel.getDescription()) .withIdentity(timingModel.getTaskName(), timingModel.getGroupName()) .build(); // 构建触发器 Trigger trigger = triggerManager.build(timingModel); // 将任务参数放入触发器中 if (timingModel.getParam() != null && !timingModel.getParam().isEmpty()) { trigger.getJobDataMap().putAll(timingModel.getParam()); } // 启动任务 scheduler.scheduleJob(jobDetail, trigger); } /** * 更新任务,任务的标示(由taskName和groupName组成)不变,任务的触发器(触发频率)发生变化 * * @param timingModel 任务model * @author YuanXiaohan * @date 2021/12/16 3:15 下午 */ public void updateTask(TimingModel timingModel) throws SchedulerException { // 获取到任务 TriggerKey triggerKey = TriggerKey.triggerKey(timingModel.getTaskName(), timingModel.getGroupName()); // 构建触发器 Trigger trigger = triggerManager.build(timingModel); // 将任务参数放入触发器中 if (timingModel.getParam() != null && !timingModel.getParam().isEmpty()) { trigger.getJobDataMap().putAll(timingModel.getParam()); } // 将新的触发器绑定到任务标示上重新执行 scheduler.rescheduleJob(triggerKey, trigger); } /** * 更新任务参数 * * @param taskName 任务名 * @param groupName 任务组名 * @param param 参数 * @author YuanXiaohan * @date 2021/12/16 3:20 下午 */ public void updateTask(String taskName, String groupName, Map<String, Object> param) throws SchedulerException { // 获取到任务 TriggerKey triggerKey = TriggerKey.triggerKey(taskName, groupName); Trigger trigger = scheduler.getTrigger(triggerKey); //修改参数 trigger.getJobDataMap().putAll(param); // 将新的触发器绑定到任务标示上重新执行 scheduler.rescheduleJob(triggerKey, trigger); } /** * 删除任务 * * @param taskName 任务名 * @param groupName 任务组 * @author YuanXiaohan * @date 2021/12/16 3:23 下午 */ public void deleteTask(String taskName, String groupName) throws SchedulerException { // 暂停任务对应的触发器 scheduler.pauseTrigger(TriggerKey.triggerKey(taskName, groupName)); // 删除任务对应的触发器 scheduler.unscheduleJob(TriggerKey.triggerKey(taskName, groupName)); // 删除任务 scheduler.deleteJob(JobKey.jobKey(taskName, groupName)); } /** * 暂停任务 * * @param taskName 添加任务时timingMode中的taskName * @param groupName 添加任务时timingMode中的groupName * @author YuanXiaohan * @date 2021/12/16 3:11 下午 */ public void pauseTask(String taskName, String groupName) throws SchedulerException { scheduler.pauseJob(JobKey.jobKey(taskName, groupName)); } /** * 将暂停的任务恢复执行 * * @param taskName 添加任务时timingMode中的taskName * @param groupName 添加任务时timingMode中的groupName * @author YuanXiaohan * @date 2021/12/16 3:13 下午 */ public void resumeTask(String taskName, String groupName) throws SchedulerException { scheduler.resumeJob(JobKey.jobKey(taskName, groupName)); } /** * 启动所有任务 * * @author YuanXiaohan * @date 2021/12/16 3:25 下午 */ public void startAllTasks() { try { scheduler.start(); } catch (Exception e) { throw new RuntimeException(e); } } /** * 关闭定时任务,回收所有的触发器资源 * * @author YuanXiaohan * @date 2021/12/16 3:26 下午 */ public void shutdownAllTasks() { try { if (!scheduler.isShutdown()) { scheduler.shutdown(); } } catch (Exception e) { throw new RuntimeException(e); } } /** * 获取所有的任务,暂时无法获取到任务执行类和任务描述 * * @return java.util.List<org.demo.quartz.mode.TimingModel> * @author YuanXiaohan * @date 2021/12/16 3:37 下午 */ public List<TimingModel> getTaskList() throws SchedulerException { GroupMatcher<JobKey> matcher = GroupMatcher.anyJobGroup(); Set<JobKey> jobKeys = scheduler.getJobKeys(matcher); List<TimingModel> taskList = new ArrayList<>(); for (JobKey jobKey : jobKeys) { List<? extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey); for (Trigger trigger : triggers) { TimingModel timingModel; if (trigger instanceof CronTrigger) { timingModel = new CronTimingModel(null, jobKey.getName(), jobKey.getGroup(), null, ((CronTrigger) trigger).getCronExpression()); timingModel.setTaskStatus(scheduler.getTriggerState(trigger.getKey()).name()); taskList.add(timingModel); } else { log.warn("name:{},group:{}的定时任务类型未知,请拓展QuartzTaskManager.getTaskList的任务类型解析", jobKey.getName(), jobKey.getGroup()); } } } return taskList; } /** * 校验定时调度器是否初始化完成 * * @author YuanXiaohan * @date 2021/12/16 2:28 下午 */ private void checkTimingInit() { if (!initStatus) { throw new TimingException("定时器未初始化,添加定时器失败!"); } } }
4. Quartz注入到SpringBoot
package org.demo.quartz.config; import org.quartz.spi.TriggerFiredBundle; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.config.AutowireCapableBeanFactory; import org.springframework.scheduling.quartz.AdaptableJobFactory; import org.springframework.stereotype.Component; /** * @author Xiaohan.Yuan * @version 1.0.0 * @ClassName TaskJobFactory.java * @Description 将Quartz注入springboot * @createTime 2021年12月16日 */ @Component public class TaskJobFactory extends AdaptableJobFactory { private final AutowireCapableBeanFactory capableBeanFactory; public TaskJobFactory(AutowireCapableBeanFactory capableBeanFactory) { this.capableBeanFactory = capableBeanFactory; } @Override protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception { //调用父类的方法 Object jobInstance = super.createJobInstance(bundle); //进行注入 capableBeanFactory.autowireBean(jobInstance); return jobInstance; } }
5. 执行
package org.demo; import org.demo.quartz.QuartzTaskManager; import org.demo.quartz.mode.CronTimingModel; import org.demo.quartz.mode.IntervalTimingMode; import org.demo.quartz.mode.TriggerType; import org.demo.quartz.task.TestQuartz; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import java.util.HashMap; @SpringBootApplication public class QuartzApplication implements CommandLineRunner { public static void main(String[] args) { SpringApplication.run(QuartzApplication.class, args); } @Override public void run(String... args) throws Exception { //构建CRON定时 //CronTimingModel cronTimingModel = new CronTimingModel(TestQuartz.class, "测试名", "测试组", "测试描述", "*/1 * * * * ?"); // 构建固定间隔定时 IntervalTimingMode intervalTimingMode = new IntervalTimingMode(TestQuartz.class, "测试名", "测试组", "测试描述", TriggerType.INTERVAL_SECOND, 5L,null); HashMap<String, Object> param = new HashMap<>(); param.put("paramKey","获取到参数了"); intervalTimingMode.setParam(param); QuartzTaskManager.getInstance().addTask(intervalTimingMode); } }
5.1 执行结果
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.6.1) 2021-12-16 18:46:55.763 INFO 46460 --- [ main] org.demo.QuartzApplication : Starting QuartzApplication using Java 11.0.11 on xiaohandeiMac.local with PID 46460 (/Users/xiaohan/IdeaProjects/demo-quartz/target/classes started by xiaohan in /Users/xiaohan/IdeaProjects/demo-quartz) 2021-12-16 18:46:55.764 INFO 46460 --- [ main] org.demo.QuartzApplication : No active profile set, falling back to default profiles: default 2021-12-16 18:46:56.089 INFO 46460 --- [ main] org.quartz.impl.StdSchedulerFactory : Using default implementation for ThreadExecutor 2021-12-16 18:46:56.095 INFO 46460 --- [ main] org.quartz.core.SchedulerSignalerImpl : Initialized Scheduler Signaller of type: class org.quartz.core.SchedulerSignalerImpl 2021-12-16 18:46:56.095 INFO 46460 --- [ main] org.quartz.core.QuartzScheduler : Quartz Scheduler v.2.3.2 created. 2021-12-16 18:46:56.096 INFO 46460 --- [ main] org.quartz.simpl.RAMJobStore : RAMJobStore initialized. 2021-12-16 18:46:56.096 INFO 46460 --- [ main] org.quartz.core.QuartzScheduler : Scheduler meta-data: Quartz Scheduler (v2.3.2) 'quartzScheduler' with instanceId 'NON_CLUSTERED' Scheduler class: 'org.quartz.core.QuartzScheduler' - running locally. NOT STARTED. Currently in standby mode. Number of jobs executed: 0 Using thread pool 'org.quartz.simpl.SimpleThreadPool' - with 10 threads. Using job-store 'org.quartz.simpl.RAMJobStore' - which does not support persistence. and is not clustered. 2021-12-16 18:46:56.096 INFO 46460 --- [ main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler 'quartzScheduler' initialized from an externally provided properties instance. 2021-12-16 18:46:56.096 INFO 46460 --- [ main] org.quartz.impl.StdSchedulerFactory : Quartz scheduler version: 2.3.2 2021-12-16 18:46:56.096 INFO 46460 --- [ main] org.quartz.core.QuartzScheduler : JobFactory set to: org.springframework.scheduling.quartz.SpringBeanJobFactory@2d6aca33 2021-12-16 18:46:56.099 INFO 46460 --- [ main] org.quartz.core.QuartzScheduler : Scheduler quartzScheduler_$_NON_CLUSTERED started. 2021-12-16 18:46:56.147 INFO 46460 --- [ main] org.demo.QuartzApplication : Started QuartzApplication in 0.589 seconds (JVM running for 6.058) 1 2021-12-16 18:46:56.156 INFO 46460 --- [eduler_Worker-1] org.demo.quartz.task.TestQuartz : ---------------------- 任务组:测试名 任务名:测试组 任务描述:测试描述 获取参数paramKey:获取到参数了 ---------------------- 2 2021-12-16 18:47:01.155 INFO 46460 --- [eduler_Worker-2] org.demo.quartz.task.TestQuartz : ---------------------- 任务组:测试名 任务名:测试组 任务描述:测试描述 获取参数paramKey:获取到参数了 ---------------------- 3 2021-12-16 18:47:06.151 INFO 46460 --- [eduler_Worker-3] org.demo.quartz.task.TestQuartz : ---------------------- 任务组:测试名 任务名:测试组 任务描述:测试描述 获取参数paramKey:获取到参数了 ----------------------
源码
-
Springboot集成quartz
2021-11-04 14:20:41#该依赖有spring对quartz的支持 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <dependency>...1.添加依赖
#该依赖有spring对quartz的支持 <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz</artifactId> <version>2.2.1</version> </dependency> <dependency> <groupId>org.quartz-scheduler</groupId> <artifactId>quartz-jobs</artifactId> <version>2.2.1</version> </dependency>
2.实现思路
参考https://blog.csdn.net/lkl_csdn/article/details/73613033
https://www.jianshu.com/p/e95d6764b4d9自定义注解标注在定时任务类和定时方法上
定义实体类,包含类名、方法名,状态等属性
定义一个扫描类,实现ApplicationContextAware接口和InitializingBean,获取到ApplicationContext对象,利用ApplicationContext对象获取到所有标注了自定义注解的类,然后拿到所有标注了自定义注解的方法,将属性插入到数据库。覆盖afterPropertiesSet方法,在该方法中调用上述方法。
定义工具类ApplicationContextUtil,利用ApplicationContextUtil根据全类名获取具体的对象。再拿到对象下所有标注了自定义注解的方法,执行该方法
定义监听器类实现ApplicationListener接口,去数据库查询所有定时任务,如果状态为null,则设为running,并修改数据库数据,把它添加到Scheduler。如果状态为not running ,则暂停该任务,最后调用start方法启动Scheduler。
实现job接口,覆盖execute方法,调用上述工具类方法
定义Controller和Service,在service中注入SchedulerFactoryBean,想直接引用SchedulerFactoryBean,要先把它注入到ioc容器中,使用@component注解+bean注解注入SchedulerFactoryBean。利用SchedulerFactoryBean来获取Scheduler,并且用Scheduler定义一个start方法。提供动态调度定时任务的接口。 -
SpringBoot集成Quartz
2021-07-16 23:55:01目的:订单 --》Quartz / 延迟队列 / 前端定时器 1、订单未支付倒计时取消 (支付超时) 2、支付之后收获的待确认 (自动确认) ---- 收了货不确认,平台就不会把钱打给 总共4类型订单 1、领养 2、服务 3、... -
SpringBoot集成Quartz框架
2021-12-24 15:28:35SpringBoot集成Quartz框架 (一)集成环境: Win10系统 JDK版本:11.0.13 SpringBoot版本:2.3.4。RELEASE Quartz版本:2.3.2 (二)代码实现 前期准备: 1.创建一个空项目springboot-demo 2.... -
quartz:SpringBoot 集成 Quartz 实现可控的任务
2021-04-28 20:48:42SpringBoot 集成 Quartz 实现可控的任务 建立数据库,运行脚本,数据库sql脚本位于 quartz\src\main\resources\schema\schema-mysql.sql。 修改Spring boot配置文件相应的数据库连接参数。 运行Spring-Boot项目。 ... -
SpringBoot与Quartz集成实现分布式定时任务集群的代码实例
2020-08-26 05:43:51今天小编就为大家分享一篇关于SpringBoot与Quartz集成实现分布式定时任务集群的代码实例,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧 -
SpringBoot集成Quartz(定时任务)
2022-01-24 21:44:44quartz是OpenSymphony开源组织在Job scheduling领域的开源项目,是由java开发的一个开源的任务日程管理系统。 quartz能做什么? 作业调度:调用各种框架的作业脚本,例如shell,hive等。 定时任务:在某一预定的时刻... -
springboot集成quartz,简版-通俗易懂
2020-11-06 14:21:10文章导航springboot使用quartz执行任务添加POM依赖1. 任务调度器2. 启动项目时将quartz也启动3. 需要执行的业务任务cron表达式生成工具类测试代码 springboot使用quartz执行任务 添加POM依赖 <dependency> &... -
SpringBoot集成Quartz数据库配置定时任务
2021-09-28 11:11:04Spring Boot 整合 Quartz 实现定时任务集群 文章参考 https://blog.csdn.net/l18848956739/article/details/86597709 https://blog.csdn.net/xibei19921101/article/details/105012749 ... -
SpringBoot集成Quartz实现动态定时任务
2022-05-19 17:06:33一、Quartz 简介 Quartz 是 OpenSymphony 开源组织在 Job Scheduling 领域又一个开源项目,是完全由 Java 开发的一个开源任务日程管理系统,“任务进度管理器”就是一个在预先确定(被纳入日程)的时间到达时,负责... -
SpringBoot集成quartz实现动态定时任务
2021-09-11 17:08:29SpringBoot集成quartz实现动态定时任务 (1)Quartz简介 Quartz三大组件: 一、调度器scheduler 二、任务job 三、触发器tigger 1、job:job是一个接口,通过实现job接口,可实现需要定时执行的代码逻辑。 2、... -
SpringBoot 集成 Quartz 实现定时任务功能
2022-07-12 10:32:39定时任务功能 -
quartz介绍 及 springboot集成quartz
2021-07-16 15:39:00一,quartz介绍 1,调度器:scheduler 任务调度的控制器,负责定时任务的调度,并提供任务和触发器的增删改查等api方法。 2,任务:job job是实际被调度的任务,每个任务必须指定具体执行任务的实现类,实现类需要... -
SpringBoot集成Quartz实现定时任务的方法
2020-08-19 05:59:40Quartz是一个定时任务框架,其他介绍网上也很详尽。这里要介绍一下Quartz里的几个非常核心的接口。通过实例代码给大家讲解SpringBoot集成Quartz实现定时任务的方法,感兴趣的朋友一起看看吧 -
springboot集成 quartz定时任务 数据库动态配置
2022-05-06 11:57:28步骤 1.定时刷新数据库表中数据,如果是新增的数据则创建新的任务,如果只是针对时间修改的任务,则刷新改任务的时间 2.网络上的很多都是一个任务,没谈论到多个任务的案例 ------------------------------------... -
springboot整合Quartz实现动态配置定时任务的方法
2020-08-29 03:56:31本篇文章主要介绍了springboot整合Quartz实现动态配置定时任务的方法,非常具有实用价值,需要的朋友可以参考下 -
springboot整合quartz定时任务yml文件配置方式
2021-03-23 09:59:45spring-cloud-alibaba+dubbo+nacos+quartz以yml配置方式实现 -
springboot集成quartz实现分布式任务调度
2021-06-24 16:38:24分布式部署的微服务架构,springboot自带的定时器无法满足我们的场景,这时候我们需要集成一套支持分布式调度的框架来解决。 首先我们去quartz官网下载 下载地址:[添加链接描述]... -
springboot集成quartz2.3.0
2021-03-13 19:36:14序quartz是java里头定时任务的经典开源实现,这里讲述一下如何在springboot中集成quartz。mavenorg.springframeworkspring-txorg.springframeworkspring-context-supportorg.quartz-schedulerquartz${quartz.version... -
Springboot集成Quartz(任务存储在数据库)
2021-08-25 10:35:161、什么是Quartz quartz是一个功能丰富的开源的任务调用系统,它可以定义很多job并发执行,支持事务和集群 2、可以做什么 定义任务,在任何时刻,或者某一时刻可以做想执行的任务 3、Quartz 三要素: Scheduler:... -
SpringBoot集成Quartz无法实现@Autowired自动注入
2022-01-05 15:42:19这两天在纠结一个问题,以前的项目由SSM转为...今天在stackflow上看到一篇文章解决了我的问题,因为springboot项目中引用了devtools,而阻止了quartz对bean的实例创建而导致,依赖中删除devtools的引用,问题解决。 ... -
SpringBoot集成Quartz实现持久化存储和可视化页面管理
2020-11-07 22:46:45本文主要是Springboot集成Quartz实现定时任务的数据库存储以及前端页面的可视化管理,所使用的主要工具有:Springboot、Mybatis-Plus、Quartz、Layui、Mysql等 正文 1.准备环境 1.创建数据库 因为本例子中业务数据和...