- <dependency>
-
- <groupId>org.springframework.bootgroupId>
-
- <artifactId>spring-boot-starter-quartzartifactId>
-
- dependency>
Quartz可以通过org.quartz.Trigger.class去拓展定时类型的,目前需求需要支持CRON和固定间隔两种定时类型,后期需要支持跳过节假日、周一~周五、周末等需求,所以需要让定时类型支持拓展。
- 1.1定时类型
- /**
- *
- * 定时类型触发器类型
- * @author jiangwei
- *
- */
-
- public enum TriggerType {
-
-
-
- /**
- * 标准CRON支持
- */
-
- CRON("标准CRON支持"),
-
- /**
- * 固定间隔毫秒
- */
-
- INTERVAL_MILLISECOND("固定间隔毫秒"),
-
- /**
- * 固定间隔秒
- */
-
- INTERVAL_SECOND("固定间隔秒"),
-
- /**
- * 固定间隔分钟
- */
-
- INTERVAL_MINUTE("固定间隔分钟"),
-
- /**
- * 固定间隔小时
- */
-
- INTERVAL_HOUR("固定间隔小时"),
-
- /**
- * 工作日,跳过节假日
- */
-
- WEEKDAYS("工作日,跳过节假日"),
-
- /**
- * 节假日
- */
-
- HOLIDAY("节假日")
-
- ;
-
-
-
-
-
- private String describe;
-
-
-
- TriggerType(String describe) {
-
- this.describe = describe;
-
- }
-
-
-
- public String getDescribe() {
-
- return describe;
-
- }
-
-
-
- public void setDescribe(String describe) {
-
- this.describe = describe;
-
- }
-
-
-
- }
我们需要构建不同的定时类型,不同的定时类型需要的参数也是不同的,因此我们需要抽象出定时的公用参数,将不同的参数多态实现
- /**
- * 构建定时任务基础对象
- * @author jiangwei
- *
- */
-
- public class TaskInfo {
-
-
-
- /**
- * 该定时的任务处理器
- */
-
- private Class extends QuartzTaskJob> taskClass;
-
-
-
- /**
- * 任务名
- */
-
- private String taskName;
-
- /**
- * 任务组名
- * */
-
- private String groupName;
-
-
-
- /**
- * 任务描述
- * */
-
- private String description;
-
-
-
-
-
- /**
- * 任务类型
- */
-
- private TriggerType type;
-
-
-
-
-
- /**
- * 任务参数,可在具体的QuartzTaskJob实现中获取这些参数
- * */
-
- private Map
param; -
-
-
- /**
- * 任务状态
- * */
-
- private String taskStatus;
-
-
-
- public TaskInfo(Class extends QuartzTaskJob> taskClass, String taskName, String groupName, String description, TriggerType type, Map
param) { -
- this.taskClass = taskClass;
-
- this.taskName = taskName;
-
- this.groupName = groupName;
-
- this.description = description;
-
- this.type = type;
-
- this.param = param;
-
- }
-
-
-
- public TaskInfo(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;
-
- }
-
-
-
- public Class extends QuartzTaskJob> getTaskClass() {
-
- return taskClass;
-
- }
-
-
-
- public void setTaskClass(Class extends QuartzTaskJob> taskClass) {
-
- this.taskClass = taskClass;
-
- }
-
-
-
- public String getTaskName() {
-
- return taskName;
-
- }
-
-
-
- public void setTaskName(String taskName) {
-
- this.taskName = taskName;
-
- }
-
-
-
- public String getGroupName() {
-
- return groupName;
-
- }
-
-
-
- public void setGroupName(String groupName) {
-
- this.groupName = groupName;
-
- }
-
-
-
- public String getDescription() {
-
- return description;
-
- }
-
-
-
- public void setDescription(String description) {
-
- this.description = description;
-
- }
-
-
-
- public TriggerType getType() {
-
- return type;
-
- }
-
-
-
- public void setType(TriggerType type) {
-
- this.type = type;
-
- }
-
-
-
- public Map
getParam() { -
- return param;
-
- }
-
-
-
- public void setParam(Map
param) { -
- this.param = param;
-
- }
-
-
-
- public String getTaskStatus() {
-
- return taskStatus;
-
- }
-
-
-
- public void setTaskStatus(String taskStatus) {
-
- this.taskStatus = taskStatus;
-
- }
-
- }
- /**
- * 用以构建CRON定时任务
- * cron触发器
- * @author jiangwei
- *
- */
-
- public class CronInfo extends TaskInfo{
-
- /**
- * cron表达式
- * */
-
- private String cronExpression;
-
-
-
- public CronInfo(Class extends QuartzTaskJob> taskClass, String taskName, String groupName, String description,
- Map
param,String cronExpression) { -
- super(taskClass, taskName, groupName, description, TriggerType.CRON, param);
-
- this.cronExpression = cronExpression;
-
- }
-
-
-
- public CronInfo(Class extends QuartzTaskJob> taskClass, String taskName, String groupName,
- String description,String cronExpression) {
-
- super(taskClass, taskName, groupName, description, TriggerType.CRON);
-
- this.cronExpression = cronExpression;
-
- }
-
-
-
- public String getCronExpression() {
-
- return cronExpression;
-
- }
-
-
-
- public void setCronExpression(String cronExpression) {
-
- this.cronExpression = cronExpression;
-
- }
-
-
-
-
-
- }
- /**
- * 用以构建固定间隔定时任务
- * @author jiangwei
- *
- */
-
- public class IntervalInfo extends TaskInfo{
-
- /**
- * 事件间隔,根据TriggerType确定单位,除了数值为毫秒,该数值必须在-2^32~2^31 (-2147483648 ~ 2147483647)
- * */
-
- private Long interval;
-
-
-
- /**
- * 重复次数,会执行该数值+1次,为空无限重复
- * */
-
- private Integer repeatCount;
-
-
-
- public IntervalInfo(Class extends QuartzTaskJob> taskClass, String taskName, String groupName, String description,
- TriggerType type, Map
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 TaskException("interval超出范围,除了类型为INTERVAL_MILLISECOND的数据间隔定时的interval范围必须在-2^32~2^31 (-2147483648 ~ 2147483647)");
-
- }
-
- }
-
- this.interval = interval;
-
- this.repeatCount = repeatCount;
-
- }
-
-
-
- public IntervalInfo(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 TaskException("interval超出范围,除了类型为INTERVAL_MILLISECOND的数据间隔定时的interval范围必须在-2^32~2^31 (-2147483648 ~ 2147483647)");
-
- }
-
- }
-
- this.interval = interval;
-
- this.repeatCount = repeatCount;
-
- }
-
-
-
- public Long getInterval() {
-
- return interval;
-
- }
-
-
-
- public void setInterval(Long interval) {
-
- this.interval = interval;
-
- }
-
-
-
- public Integer getRepeatCount() {
-
- return repeatCount;
-
- }
-
-
-
- public void setRepeatCount(Integer repeatCount) {
-
- this.repeatCount = repeatCount;
-
- }
-
-
-
-
-
- }
- /**
- * 抽象任务类
- * @author jiangwei
- *
- */
-
- public interface QuartzTaskJob extends Job{
-
-
-
- /**
- * 执行定时任务
- */
-
- @Override
-
- void execute(JobExecutionContext context) throws JobExecutionException;
-
-
-
- }
- /**
- * 实现一个测试任务
- * @author jiangwei
- *
- */
-
- @Component
-
- public class TestQuartz implements QuartzTaskJob{
-
-
-
- private Logger log=LoggerFactory.getLogger(TestQuartz.class);
-
-
-
- @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();
-
- }
-
- }
-
- }
- /**
- * 触发器工厂
- *
- * @author jiangwei
- *
- */
-
- public interface ITriggerFactory {
-
-
-
-
-
- /**
- * 判断是否为该类型的触发器
- *
- * @param triggerType 触发器类型
- * @return boolean 如果是该类型的触发器返回true 否则返回false
- */
-
- public boolean check(TriggerType triggerType);
-
-
-
- /**
- * 创建触发器
- * @param taskInfo:定时任务基础信息
- * @return Trigger
- */
-
- public Trigger build(TaskInfo taskInfo);
-
-
-
- }
- /**
- *
- * CRON触发器
- *
- * @author jiangwei
- *
- */
-
- @Component
-
- public class CronTrigger implements ITriggerFactory{
-
-
-
- @Override
-
- public boolean check(TriggerType triggerType) {
-
- return triggerType==TriggerType.CRON;
-
- }
-
-
-
- @Override
-
- public Trigger build(TaskInfo taskInfo) {
-
- if (!(taskInfo instanceof CronInfo)){
-
- throw new TaskException("构建类型为CRON定时必须传入CronTimingModel.class的实现类");
-
- }
-
- //按新的cronExpression表达式构建一个新的trigger
-
- CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(((CronInfo) taskInfo).getCronExpression());
-
- return TriggerBuilder.newTrigger().withIdentity(taskInfo.getTaskName(), taskInfo.getTaskName())
-
- .withSchedule(scheduleBuilder).build();
-
- }
-
-
-
- }
- /**
- *
- * 固定间隔触发器
- *
- * @author jiangwei
- *
- */
-
- @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(TaskInfo taskInfo) {
-
- if (!(taskInfo instanceof IntervalInfo)){
-
- throw new TaskException("构建类型为INTERVAL定时必须传入IntervalTimingMode.class的实现类");
-
- }
-
- //创建触发器
-
- SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
-
- Long interval = ((IntervalInfo) taskInfo).getInterval();
-
- Integer repeatCount = ((IntervalInfo) taskInfo).getRepeatCount();
-
- switch (taskInfo.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;
-
- default:
-
- break;
-
- }
-
- if (repeatCount==null){
-
- // 无限重复
-
- simpleScheduleBuilder.repeatForever();
-
- }else {
-
- simpleScheduleBuilder.withRepeatCount(repeatCount);
-
- }
-
- return TriggerBuilder.newTrigger().withIdentity(taskInfo.getTaskName(), taskInfo.getTaskName())
-
- .withSchedule(simpleScheduleBuilder).build();
-
- }
-
-
-
- }
- /**
- *
- * 构建触发器工厂
- * 触发器管理器, 用来生成触发器
- *
- * @author jiangwei
- *
- */
-
- @Component
-
- public class TriggerManager {
-
-
-
- private final List
triggerFactories; -
-
-
- public TriggerManager(List
triggerFactories) { -
- this.triggerFactories = triggerFactories;
-
- }
-
-
-
- /**
- * 生成对应的触发器
- *
- * @param timingModel 触发器model
- * @return org.quartz.Trigger
- * @author YuanXiaohan
- * @date 2021/12/16 2:53 下午
- */
-
- public Trigger build(TaskInfo taskInfo) {
-
- for (ITriggerFactory triggerFactory : triggerFactories) {
-
- if (triggerFactory.check(taskInfo.getType())) {
-
- return triggerFactory.build(taskInfo);
-
- }
-
- }
-
- return null;
-
- }
-
-
-
- }
- /**
- * 构建定时管理类
- *
- * 添加定时
- * 更新定时触发器
- * 更新任务参数
- * 删除任务
- * 暂停任务
- * 将暂停的任务恢复执行
- * 启动所有任务
- * 关闭定时任务
- * 获取所有任务
- * @author jiangwei
- *
- */
-
- @Configuration
-
- public class QuartzTaskManager {
-
-
-
- private Logger log=LoggerFactory.getLogger(QuartzTaskManager.class);
-
-
-
- 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
- */
-
- public void addTask(TaskInfo taskInfo) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException,
-
- InstantiationException, SchedulerException {
-
- checkTimingInit();
-
- // 构建任务信息
-
- JobDetail jobDetail = JobBuilder.newJob(taskInfo.getTaskClass().getDeclaredConstructor().newInstance().getClass())
-
- .withDescription(taskInfo.getDescription())
-
- .withIdentity(taskInfo.getTaskName(), taskInfo.getGroupName())
-
- .build();
-
-
-
- // 构建触发器
-
- Trigger trigger = triggerManager.build(taskInfo);
-
- // 将任务参数放入触发器中
-
- if (taskInfo.getParam() != null && !taskInfo.getParam().isEmpty()) {
-
- trigger.getJobDataMap().putAll(taskInfo.getParam());
-
- }
-
- // 启动任务
-
- scheduler.scheduleJob(jobDetail, trigger);
-
- }
-
-
-
- /**
- * 更新任务,任务的标示(由taskName和groupName组成)不变,任务的触发器(触发频率)发生变化
- *
- * @param timingModel 任务model
- */
-
- public void updateTask(TaskInfo taskInfo) throws SchedulerException {
-
- // 获取到任务
-
- TriggerKey triggerKey = TriggerKey.triggerKey(taskInfo.getTaskName(), taskInfo.getGroupName());
-
-
-
- // 构建触发器
-
- Trigger trigger = triggerManager.build(taskInfo);
-
- // 将任务参数放入触发器中
-
- if (taskInfo.getParam() != null && !taskInfo.getParam().isEmpty()) {
-
- trigger.getJobDataMap().putAll(taskInfo.getParam());
-
- }
-
- // 将新的触发器绑定到任务标示上重新执行
-
- scheduler.rescheduleJob(triggerKey, trigger);
-
- }
-
-
-
- /**
- * 更新任务参数
- *
- * @param taskName 任务名
- * @param groupName 任务组名
- * @param param 参数
- */
-
- public void updateTask(String taskName, String groupName, Map
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 任务组
- */
-
- 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
- */
-
- public void pauseTask(String taskName, String groupName) throws SchedulerException {
-
- scheduler.pauseJob(JobKey.jobKey(taskName, groupName));
-
- }
-
-
-
-
-
- /**
- * 将暂停的任务恢复执行
- *
- * @param taskName 添加任务时timingMode中的taskName
- * @param groupName 添加任务时timingMode中的groupName
- */
-
- public void resumeTask(String taskName, String groupName) throws SchedulerException {
-
- scheduler.resumeJob(JobKey.jobKey(taskName, groupName));
-
- }
-
-
-
- /**
- * 启动所有任务
- *
- */
-
- public void startAllTasks() {
-
- try {
-
- scheduler.start();
-
- } catch (Exception e) {
-
- throw new RuntimeException(e);
-
- }
-
- }
-
-
-
- /**
- * 关闭定时任务,回收所有的触发器资源
- *
- */
-
- public void shutdownAllTasks() {
-
- try {
-
- if (!scheduler.isShutdown()) {
-
- scheduler.shutdown();
-
- }
-
- } catch (Exception e) {
-
- throw new RuntimeException(e);
-
- }
-
- }
-
-
-
-
-
- /**
- * 获取所有的任务,暂时无法获取到任务执行类和任务描述
- *
- * @return java.util.List
- * @author YuanXiaohan
- * @date 2021/12/16 3:37 下午
- */
-
- public List
getTaskList() throws SchedulerException { -
- GroupMatcher
matcher = GroupMatcher.anyJobGroup(); -
- Set
jobKeys = scheduler.getJobKeys(matcher); -
- List
taskList = new ArrayList(); -
- for (JobKey jobKey : jobKeys) {
-
- List extends Trigger> triggers = scheduler.getTriggersOfJob(jobKey);
-
- for (Trigger trigger : triggers) {
-
- TaskInfo taskInfo;
-
- if (trigger instanceof CronTrigger) {
-
- taskInfo = new CronInfo(null, jobKey.getName(), jobKey.getGroup(), null, ((CronTrigger) trigger).getCronExpression());
-
- taskInfo.setTaskStatus(scheduler.getTriggerState(trigger.getKey()).name());
-
- taskList.add(taskInfo);
-
- } else {
-
- log.warn("name:{},group:{}的定时任务类型未知,请拓展QuartzTaskManager.getTaskList的任务类型解析", jobKey.getName(), jobKey.getGroup());
-
- }
-
- }
-
- }
-
- return taskList;
-
- }
-
-
-
-
-
- /**
- * 校验定时调度器是否初始化完成
- */
-
- private void checkTimingInit() {
-
- if (!initStatus) {
-
- throw new TaskException("定时器未初始化,添加定时器失败!");
-
- }
-
- }
-
-
-
- }
- /**
- * Quartz注入到SpringBoot
- * @author jiangwei
- *
- */
-
- @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;
-
- }
-
-
-
- }
- public class JwbastaThymeleafAdminApplicaiton implements CommandLineRunner{
-
-
-
- private static Logger logger=LoggerFactory.getLogger(JwbastaThymeleafAdminApplicaiton.class);
-
-
-
- public static void main(String[] args) {
-
- SpringApplication.run(JwbastaThymeleafAdminApplicaiton.class, args);
-
- }
-
-
-
- }
-
-
-
- @Override
-
- public void run(String... args) throws Exception {
-
- //构建CRON定时
-
- //CronTimingModel cronTimingModel = new CronTimingModel(TestQuartz.class, "测试名", "测试组", "测试描述", "*/1 * * * * ?");
-
- // 构建固定间隔定时
-
- IntervalInfo intervalTimingMode = new IntervalInfo(TestQuartz.class, "测试名", "测试组", "测试描述", TriggerType.INTERVAL_SECOND, 5L,null);
-
- HashMap
param = new HashMap<>(); -
- param.put("paramKey","获取到参数了");
-
- intervalTimingMode.setParam(param);
-
- QuartzTaskManager.getInstance().addTask(intervalTimingMode);
-
- }
-
-
-
- }