先来介绍一下 SpringBoot 这个框架。SpringBoot 是一款基于 Spring 框架的快速开发框架,能够帮助开发者快速搭建 Spring 应用,极大地提高了开发效率。在 SpringBoot 中,我们可以非常简单地创建定时任务并进行动态执行,下面是详解 SpringBoot 创建定时任务(配合数据库动态执行)的攻略:
一、引入相关依赖
在创建我们的 SpringBoot 项目时,需要在 pom.xml 中加上以下依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-quartz</artifactId>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.3.0</version>
</dependency>
其中,spring-boot-starter-data-jdbc 是 SpringBoot 自带的 JDBC 数据库框架,spring-boot-starter-quartz 是帮助我们管理定时任务的框架,quartz-jobs 是 Quartz 任务调度框架的依赖。
二、编写定时任务
下面为一个简单的固定执行时间的定时任务,代码如下:
@Component
public class HelloJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("Hello World!");
}
}
@Configuration
public class QuartzConfig {
@Bean
public JobDetail helloJobDetail() {
return JobBuilder.newJob(HelloJob.class).withIdentity("helloJob").storeDurably().build();
}
@Bean
public Trigger helloJobTrigger() {
return TriggerBuilder.newTrigger().forJob(helloJobDetail()).withIdentity("helloJobTrigger")
.withSchedule(CronScheduleBuilder.cronSchedule("0/5 * * * * ?")).build();
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setJobDetails(helloJobDetail());
factory.setTriggers(helloJobTrigger());
return factory;
}
}
HelloJob 实现了 Quartz 的 Job 接口,我们可以在 execute 方法中编写我们的业务逻辑。QuartzConfig 配置类中定义了 helloJobDetail 和 helloJobTrigger 两个 Bean,用于定义 Job 和 Trigger 的具体信息,并指定在何时执行。同时,我们在 schedulerFactoryBean 中通过设置 JobDetails 和 Triggers 来将 Job 和 Trigger 关联起来。在 Cron 表达式中设置定时任务执行时间,这里我们设置的是每 5 秒执行一次。
在以上代码中,我们使用了 Quartz 的 CronScheduleBuilder 类来设置定时任务的执行时间,以下是几个常用的 Cron 表达式:
- "0/5 * * * * ?":每 5 秒执行一次
- "0 0 12 * * ?":每天中午 12 点执行
- "0 15 10 ? * *":每天上午 10:15 执行
- "0 15 10 * * ?":每天上午 10:15 执行
- "0 15 10 * * ? *":每天上午 10:15 执行
- "0 15 10 * * ? 2019":2019 年的每天上午 10:15 执行
三、动态执行任务
接下来,我们将了解如何从数据库中动态获取任务定时时间并执行任务。
首先,我们需要定义一个接口,用于定义定时任务的服务方法:
public interface ScheduledTaskService {
/**
* 获取所有的数据库中的定时任务
* @return
*/
List<ScheduledTask> getAllScheduledTask();
/**
* 根据定时任务 ID 执行定时任务
* @param scheduledTaskId
*/
void executeTask(Integer scheduledTaskId);
}
ScheduledTaskService 接口中定义了 getAllScheduledTask 和 executeTask 两个方法,用于获取数据库中的定时任务和执行定时任务,具体实现方式如下:
@Service
public class ScheduledTaskServiceImpl implements ScheduledTaskService {
@Autowired
private ScheduledTaskDao scheduledTaskDao;
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
@Override
public List<ScheduledTask> getAllScheduledTask() {
return scheduledTaskDao.getAllScheduledTask();
}
@Override
public void executeTask(Integer scheduledTaskId) {
Optional<ScheduledTask> optionalScheduledTask = scheduledTaskDao.getScheduledTaskById(scheduledTaskId);
if (optionalScheduledTask.isPresent()) {
ScheduledTask scheduledTask = optionalScheduledTask.get();
String cronExpression = scheduledTask.getCronExpression();
JobDetail jobDetail = JobBuilder.newJob(ScheduledTaskJob.class)
.withIdentity(scheduledTask.getJobName(), scheduledTask.getJobGroup())
.storeDurably()
.build();
jobDetail.getJobDataMap().put("scheduledTaskId", scheduledTaskId);
Trigger trigger = TriggerBuilder.newTrigger()
.forJob(jobDetail)
.withIdentity(scheduledTask.getTriggerName(), scheduledTask.getTriggerGroup())
.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
.build();
try {
Scheduler scheduler = schedulerFactoryBean.getScheduler();
scheduler.addJob(jobDetail, true, true);
scheduler.scheduleJob(trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
}
ScheduledTaskServiceImpl 中使用了 ScheduledTaskDao 中定义的方法来获取数据库中的任务信息,然后通过 JobBuilder 和 TriggerBuilder 对任务和触发器进行构建,并且将任务和触发器关联,将任务存入调度中心并且执行。
另外,我们还需要定义一个 Job,用于执行定时任务。以下是该 Job 的具体实现:
@Service
public class ScheduledTaskJob implements Job {
@Autowired
private ScheduledTaskDao scheduledTaskDao;
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
JobDataMap dataMap = jobExecutionContext.getJobDetail().getJobDataMap();
Integer scheduledTaskId = (Integer) dataMap.get("scheduledTaskId");
Optional<ScheduledTask> optionalScheduledTask = scheduledTaskDao.getScheduledTaskById(scheduledTaskId);
if (optionalScheduledTask.isPresent()) {
ScheduledTask scheduledTask = optionalScheduledTask.get();
// TODO 执行具体的任务逻辑
System.out.println(new Date() + "执行定时任务:" + scheduledTask.getTaskName());
}
}
}
ScheduledTaskJob 中实现了 Quartz 的 Job 接口,并且通过 ScheduledTaskDao 从数据库中获取任务信息,然后执行具体的业务逻辑。该 Job 中的任务逻辑可以是任何我们想要执行的具体业务逻辑,比如发送邮件、统计数据、备份数据等等。
最后,我们需要定义一个存放定时任务信息的实体类 ScheduledTask:
public class ScheduledTask {
private Integer scheduledTaskId;
private String taskName;
private String jobName;
private String jobGroup;
private String triggerName;
private String triggerGroup;
private String cronExpression;
// 省略 getter 和 setter 方法
}
ScheduledTask 类中定义了任务的各项属性,包括任务 ID、任务名称、Job 名称、Job 组、Trigger 名称、Trigger 组以及任务的 Cron 表达式等。
示例讲解
接下来,我们来看两个示例,分别用于演示如何创建并执行定时任务。
首先,我们来创建一个每分钟执行一次的任务。
- 假设我们已经在数据库中创建好了一条定时任务信息:
scheduled_task_id:1
task_name:每分钟执行一次的任务
job_name:job1
job_group:group1
trigger_name:trigger1
trigger_group:group1
cron_expression:0 0/1 * * * ?
@Component
public class EveryMinuteJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("This is a job which will be executed every minute.");
}
}
@Configuration
public class QuartzConfig {
@Bean(name = "everyMinuteJobDetail")
public JobDetail everyMinuteJobDetail() {
return JobBuilder.newJob(EveryMinuteJob.class).withIdentity("job1", "group1").storeDurably().build();
}
@Bean(name = "everyMinuteJobTrigger")
public Trigger everyMinuteJobTrigger() {
return TriggerBuilder.newTrigger().forJob(everyMinuteJobDetail()).withIdentity("trigger1", "group1")
.withSchedule(CronScheduleBuilder.cronSchedule("0 0/1 * * * ?")).build();
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setJobDetails(everyMinuteJobDetail());
factory.setTriggers(everyMinuteJobTrigger());
return factory;
}
}
- 然后,我们在 ScheduledTaskServiceImpl 中创建一个方法,并调用 executeTask 方法来执行该定时任务:
@Service
public class ScheduledTaskServiceImpl implements ScheduledTaskService {
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
@Override
public List<ScheduledTask> getAllScheduledTask() {
return scheduledTaskDao.getAllScheduledTask();
}
@Override
public void executeTask(Integer scheduledTaskId) {
Optional<ScheduledTask> optionalScheduledTask = scheduledTaskDao.getScheduledTaskById(scheduledTaskId);
if (optionalScheduledTask.isPresent()) {
ScheduledTask scheduledTask = optionalScheduledTask.get();
String cronExpression = scheduledTask.getCronExpression();
JobDetail jobDetail = JobBuilder.newJob(EveryMinuteJob.class)
.withIdentity(scheduledTask.getJobName(), scheduledTask.getJobGroup())
.storeDurably()
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.forJob(jobDetail)
.withIdentity(scheduledTask.getTriggerName(), scheduledTask.getTriggerGroup())
.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
.build();
try {
Scheduler scheduler = schedulerFactoryBean.getScheduler();
scheduler.addJob(jobDetail, true, true);
scheduler.scheduleJob(trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
}
- 最后,我们可以在 controller 中调用 executeTask 方法来执行该定时任务:
@RestController
@RequestMapping("/scheduledTask")
public class ScheduledTaskController {
@Autowired
private ScheduledTaskService scheduledTaskService;
@RequestMapping("/execute")
public String executeScheduledTask() {
scheduledTaskService.executeTask(1);
return "execute success.";
}
}
现在,我们来创建一个每天 10:15 执行一次的任务。
- 假设我们已经在数据库中创建好了一条定时任务信息:
scheduled_task_id:2
task_name:每天 10:15 执行一次的任务
job_name:job2
job_group:group2
trigger_name:trigger2
trigger_group:group2
cron_expression:0 15 10 ? * *
@Component
public class EveryDayJob implements Job {
@Override
public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
System.out.println("This is a job which will be executed every day at 10:15.");
}
}
@Configuration
public class QuartzConfig {
@Bean(name = "everyDayJobDetail")
public JobDetail everyDayJobDetail() {
return JobBuilder.newJob(EveryDayJob.class).withIdentity("job2", "group2").storeDurably().build();
}
@Bean(name = "everyDayJobTrigger")
public Trigger everyDayJobTrigger() {
return TriggerBuilder.newTrigger().forJob(everyDayJobDetail()).withIdentity("trigger2", "group2")
.withSchedule(CronScheduleBuilder.cronSchedule("0 15 10 ? * *")).build();
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setJobDetails(everyDayJobDetail());
factory.setTriggers(everyDayJobTrigger());
return factory;
}
}
- 然后,我们在 ScheduledTaskServiceImpl 中创建一个方法,并调用 executeTask 方法来执行该定时任务:
@Service
public class ScheduledTaskServiceImpl implements ScheduledTaskService {
@Autowired
private SchedulerFactoryBean schedulerFactoryBean;
@Override
public List<ScheduledTask> getAllScheduledTask() {
return scheduledTaskDao.getAllScheduledTask();
}
@Override
public void executeTask(Integer scheduledTaskId) {
Optional<ScheduledTask> optionalScheduledTask = scheduledTaskDao.getScheduledTaskById(scheduledTaskId);
if (optionalScheduledTask.isPresent()) {
ScheduledTask scheduledTask = optionalScheduledTask.get();
String cronExpression = scheduledTask.getCronExpression();
JobDetail jobDetail = JobBuilder.newJob(EveryDayJob.class)
.withIdentity(scheduledTask.getJobName(), scheduledTask.getJobGroup())
.storeDurably()
.build();
Trigger trigger = TriggerBuilder.newTrigger()
.forJob(jobDetail)
.withIdentity(scheduledTask.getTriggerName(), scheduledTask.getTriggerGroup())
.withSchedule(CronScheduleBuilder.cronSchedule(cronExpression))
.build();
try {
Scheduler scheduler = schedulerFactoryBean.getScheduler();
scheduler.addJob(jobDetail, true, true);
scheduler.scheduleJob(trigger);
} catch (SchedulerException e) {
e.printStackTrace();
}
}
}
}
- 最后,我们可以在 controller 中调用 executeTask 方法来执行该定时任务:
@RestController
@RequestMapping("/scheduledTask")
public class ScheduledTaskController {
@Autowired
private ScheduledTaskService scheduledTaskService;
@RequestMapping("/execute")
public String executeScheduledTask() {
scheduledTaskService.executeTask(2);
return "execute success.";
}
}
至此,我们已经通过 SpringBoot 框架实现了动态创建并执行定时任务的功能。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解SpringBoot 创建定时任务(配合数据库动态执行) - Python技术站