前面添加过简单的定时任务,但这个任务启动后就会一直运行直到应用结束,如果打算不重启应用就调整任务的定时执行时间,或者暂停任务甚至动态添加新的任务呢?还是有办法做到的,下面就开始我们的扩展。
添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
代码修改
- 启动类添加@EnableScheduling注解
- 配置文件添加以下配置,第一行指定使用jdbc连接数据库,第二行配置启动时自动初始化quartz相关表,第三行配置quart数据库表文件路径,由于只需要初始化一次,所以当生成相应表后后面两行注释掉。
spring.quartz.job-store-type=jdbc
#spring.quartz.jdbc.initialize-schema=always
#spring.quartz.jdbc.schema=classpath:quartz-mysql.sql
quart数据库表文件可以在quartz scheduler官网下载发布包,这里使用的是2.2.3的版本,下载解压后进入quartz-2.2.3\docs\dbTables,复制tables_mysql_innodb.sql到项目src\main\resource目录下并修改文件名称和配置一致。
- 数据源配置,除了在配置文件配置连接数据库的相关配置外,代码中也添加以下内容:
@Bean
@Primary
public DataSourceProperties defaultDsProperties() {
return new DataSourceProperties();
}
@Bean
@QuartzDataSource //指示Quartz使用此数据源进行数据库操作
public DataSource getDataSource() {
return defaultDsProperties().initializeDataSourceBuilder().build();
}
- 自定义任务类:
public class CustJob implements Job{
@Override
public void execute(JobExecutionContext context) throws JobExecutionException {
//这里是固定的业务逻辑,方便演示只简单打印信息
System.out.println(LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME) + " -- Hello, world!!");
}
}
- 添加任务控制器类:
@RestController
@RequestMapping("/job")
public class QuartzJobController {
@Autowired
private SchedulerFactoryBean schedulerFactory;
/**
* 添加定时任务
* @param jobClassName: 自定义的任务类名称,例如:CustJob,不需要包和.class后缀
* @param jobGroupName:自定义的任务组,可随意设置
* @param cronExpression: 定时表达式
* @throws Exception
*/
@PostMapping(value = "/add")
public void addjob(@RequestParam(value = "jobClassName") String jobClassName,
@RequestParam(value = "jobGroupName") String jobGroupName,
@RequestParam(value = "cronExpression") String cronExpression) throws Exception {
// 启动调度器
Scheduler scheduler = schedulerFactory.getScheduler();
scheduler.start();
// 构建job信息
JobDetail jobDetail = JobBuilder.newJob(CustJob.class).withIdentity(jobClassName, jobGroupName).build();
// 表达式调度构建器(即任务执行的时间)
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression);
// 按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(jobClassName, jobGroupName)
.withSchedule(scheduleBuilder).build();
try {
scheduler.scheduleJob(jobDetail, trigger);
} catch (SchedulerException e) {
System.out.println("创建定时任务失败" + e);
throw new Exception("创建定时任务失败");
}
}
@PostMapping(value = "/reschedule")
public void reschedule(String jobClassName, String jobGroupName, String cronExpression) throws Exception {
try {
Scheduler scheduler = schedulerFactory.getScheduler();
TriggerKey triggerKey = TriggerKey.triggerKey(jobClassName, jobGroupName);
// 表达式调度构建器
CronTrigger trigger = (CronTrigger) scheduler.getTrigger(triggerKey);
// 按新的cronExpression表达式重新构建trigger
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(cronExpression)
.withMisfireHandlingInstructionFireAndProceed();
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
// 按新的trigger重新设置job执行
scheduler.rescheduleJob(triggerKey, trigger);
} catch (SchedulerException e) {
System.out.println("更新定时任务失败" + e);
throw new Exception("更新定时任务失败");
}
}
@PostMapping(value = "/pause")
public void pausejob(@RequestParam(value = "jobClassName") String jobClassName,
@RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
schedulerFactory.getScheduler().pauseJob(JobKey.jobKey(jobClassName, jobGroupName));
}
@PostMapping(value = "/resume")
public void resumejob(@RequestParam(value = "jobClassName") String jobClassName,
@RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
schedulerFactory.getScheduler().resumeJob(JobKey.jobKey(jobClassName, jobGroupName));
}
@PostMapping(value = "/delete")
public void deletejob(@RequestParam(value = "jobClassName") String jobClassName,
@RequestParam(value = "jobGroupName") String jobGroupName) throws Exception {
schedulerFactory.getScheduler().pauseTrigger(TriggerKey.triggerKey(jobClassName, jobGroupName));
schedulerFactory.getScheduler().unscheduleJob(TriggerKey.triggerKey(jobClassName, jobGroupName));
schedulerFactory.getScheduler().deleteJob(JobKey.jobKey(jobClassName, jobGroupName));
}
}
最后编译和启动应用,可以使用postman测试相应的接口,如果有配置swagger的话,也可以在接口文档页面中测试。
有多种动态任务的话,可以定义不同的任务类,或者修改自定义任务类并扩展Controller类接口增添一些控制参数,使得任务类支持不同的业务逻辑。
网友评论