一、简单介绍
Quartz可以对job进行简单控制,但不支持分布式,也没有管理界面和任务分片,但使用起来比较简易。
二、创建简单Demo
我们开始简单使用一下,首先创建Demo,在pom文件中加入以下依赖。
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.0.0.RELEASE</version><relativePath />
</parent><dependencies><dependency><groupId>org.quartz-scheduler</groupId><artifactId>quartz</artifactId><version>2.3.2</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>1.1.10</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.18.24</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.83</version></dependency><!--hutool工具包--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-all</artifactId><version>5.5.6</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><version>2.6.3</version></dependency><dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>2.5.6</version></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.19</version></dependency>
</dependencies>
application.yml如下。
server:port: 8090
# servlet:
# context-path: /logging:level:root: infospring:datasource:url: jdbc:mysql://127.0.0.1:3306/quartz?useUnicode=true&characterEncoding=UTF-8&rewriteBatchedStatements=true&useSSL=false&allowMultiQueries=trueusername: rootpassword: 123456
# driver-class-name: com.mysql.jdbc.Driver# 时间格式jackson:time-zone: GMT+8date-format: yyyy-MM-dd HH:mm:ssquartz:job-store-type: jdbcinitialize-schema: embedded#设置自动启动,默认为 trueauto-startup: true#启动时更新己存在的Joboverwrite-existing-jobs: trueproperties:org:quartz:scheduler:instanceName: MySchedulerinstanceId: AUTOjobStore:class: org.quartz.impl.jdbcjobstore.JobStoreTXdriverDelegateClass: org.quartz.impl.jdbcjobstore.StdJDBCDelegatetablePrefix: QRTZ_isClustered: truemisfireThreshold: 60000clusterCheckinInterval: 10000threadPool:class: org.quartz.simpl.SimpleThreadPoolthreadCount: 50threadPriority: 5threadsInheritContextClassLoaderOfInitializingThread: true
然后创建一个非常简单的Scheduler调度工厂。
@Configuration
public class QuartzConfiguration {/*** 注册调度器创建工厂*/@Beanpublic Scheduler schedulerFactoryBean() throws Exception {return StdSchedulerFactory.getDefaultScheduler();}
}
添加两个Job Detail,我们要达到的效果是先执行完Job1再执行Job2
。两个Job都需要实现Job接口的execute方法,在其中编写业务代码。
@Slf4j
public class TestJob1 implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {log.info("job1被执行,当前时间:" + new Date());}
}
@Slf4j
public class TestJob2 implements Job {@Overridepublic void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {log.info("job2被执行,当前时间:" + new Date());}
}
然后是MVC的分层,这里只写出实现层的代码。
@Slf4j
@RequiredArgsConstructor
@Service
public class ServiceImpl implements IService {final Scheduler scheduler;@Overridepublic String addTask() throws SchedulerException {//创建计划链表JobChainingJobListener listener = new JobChainingJobListener("JobLink");JobDetail job1 = JobBuilder.newJob(TestJob1.class).withIdentity("job1", "jg1").build();JobDetail job2 = JobBuilder.newJob(TestJob2.class).withIdentity("job2", "jg1")// 持久存放设置为true,不然Job2只会执行一遍.storeDurably(true).build();CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity("trigger1", "tg1").withSchedule(CronScheduleBuilder.cronSchedule("0/2 * * * * ?")).startNow().build();scheduler.addJob(job2, false, true);//设置执行顺序为先执行Job1再执行Job2listener.addJobChainLink(job1.getKey(), job2.getKey());//调度器使用计划链表scheduler.getListenerManager().addJobListener(listener);//安排调度作业scheduler.scheduleJob(job1, trigger);if (!scheduler.isShutdown()) {scheduler.start();}return "success";}
}
这样启动项目后,请求对应的接口,就可以运行起来了。
三、实现Job的动态操作
1、首先需要创建数据库表。在官网[http://www.quartz-scheduler.org/downloads/]下载项目示例后(我是用的quartz-2.3.0-SNAPSHOT),可以在org.quartz.impl.jdbcjobstore包下找到对应数据库的创建语句。
2、增加更多的接口,这里展示对应的实现类。
// 创建一个cron的任务
@Override
public void addJob(String clazzName, String jobName, String groupName, String cronExp, Map<String, Object> param) {try {// 启动调度器,默认初始化的时候已经启动scheduler.start();//构建job信息Class<? extends Job> jobClass = (Class<? extends Job>) Class.forName(clazzName);JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(jobName, groupName).build();//表达式调度构建器(即任务执行的时间)CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExp);//按新的cronExpression表达式构建一个新的triggerCronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobName, groupName).withSchedule(scheduleBuilder).build();//获得JobDataMap,写入数据if (param != null) {trigger.getJobDataMap().putAll(param);}scheduler.scheduleJob(jobDetail, trigger);} catch (Exception e) {log.error("创建任务失败", e);}
}// 暂停任务
@Override
public void pauseJob(String jobName, String groupName) {try {scheduler.pauseJob(JobKey.jobKey(jobName, groupName));} catch (SchedulerException e) {log.error("暂停任务失败", e);}
}// 恢复任务
@Override
public void resumeJob(String jobName, String groupName) {try {scheduler.resumeJob(JobKey.jobKey(jobName, groupName));} catch (SchedulerException e) {log.error("恢复任务失败", e);}
}// 启动一次
@Override
public void runOnce(String jobName, String groupName) {try {scheduler.triggerJob(JobKey.jobKey(jobName, groupName));} catch (SchedulerException e) {log.error("立即运行一次定时任务失败", e);}
}// 更新单个任务
@Override
public void updateJob(String jobName, String groupName, String cronExp, Map<String, Object> param) {try {TriggerKey triggerKey = TriggerKey.triggerKey(jobName, groupName);CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);if (cronExp != null) {// 表达式调度构建器CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExp);// 按新的cronExpression表达式重新构建triggertrigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();}//修改mapif (param != null) {trigger.getJobDataMap().putAll(param);}// 按新的trigger重新设置job执行scheduler.rescheduleJob(triggerKey, trigger);} catch (Exception e) {log.error("更新任务失败", e);}
}// 删除单个任务
@Override
public void deleteJob(String jobName, String groupName) {try {//暂停、移除、删除scheduler.pauseTrigger(TriggerKey.triggerKey(jobName, groupName));scheduler.unscheduleJob(TriggerKey.triggerKey(jobName, groupName));scheduler.deleteJob(JobKey.jobKey(jobName, groupName));} catch (Exception e) {log.error("删除任务失败", e);}
}// 开启所有的任务
@Override
public void startAllJobs() {try {scheduler.start();} catch (Exception e) {log.error("开启所有的任务失败", e);}
}// 暂停所有任务
@Override
public void pauseAllJobs() {try {scheduler.pauseAll();} catch (Exception e) {log.error("暂停所有任务失败", e);}
}// 恢复所有任务
@Override
public void resumeAllJobs() {try {scheduler.resumeAll();} catch (Exception e) {log.error("恢复所有任务失败", e);}
}// 关闭所有的任务
@Override
public void shutdownAllJobs() {try {if (!scheduler.isShutdown()) {// 需谨慎操作关闭scheduler容器// scheduler生命周期结束,无法再 start() 启动schedulerscheduler.shutdown(true);}} catch (Exception e) {log.error("关闭所有的任务失败", e);}
}
需要完整Demo可以在此处下载:https://download.csdn.net/download/qq_40579464/87603431