这是我参与8月更文挑战的第29天,活动详情查看:8月更文挑战
上篇文章学习了SpringBoot中使用@Scheduled注解实现定时任务:SpringBoot中使用@Scheduled创建定时任务
尽管使用@Scheduled注解配置定时任务是十分方便的,但是由于其设置是在注解中,因此如果需要改变当前任务的定时规划,则需要重新启动项目才可以生效。为了解决这种不能及时变更的问题,我们可以使用实现接口的方式来完成定时任务的创建。
引入依赖
由于需要实时的修改定时任务执行的规则,那么就不能将定时规则写在代码中,因此我们将定时任务规则写入数据库中,每次执行定时任务时会获取数据库中最新规则设定到任务中。 我们需要在项目中使用数据库,那么要引入MySQl、MyBatis等依赖信息:
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
<scope>compile</scope>
</dependency>
数据库中新增任务规则表和数据
在本地数据库中新增一个task表,用来记录定时任务的规则信息,
CREATE TABLE `task` (
`id` int NOT NULL PRIMARY KEY,
`cron` varchar(30) NOT NULL
);
INSERT INTO `task` VALUES (1, '* * * ? * ?');
由上述sql语句中的'* * * ? * ?'值可以看出,我们添加数据的定时任务规则是每秒执行一次。
随后在SpringBoot项目的配置文件中配置数据源信息:
spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.username=root
spring.datasource..password=123456
创建定时器类
准备好数据并配置数据源信息后,我们定义一个定时器类,并在该类上使用@EnableScheduling注解开启定时任务。
@Configuration
@EnableScheduling
public class TaskDemo implements SchedulingConfigurer {
@Mapper
public interface CronMapper {
@Select("select cron from cron limit 1")
public String getCron();
}
@Autowired
@SuppressWarnings("all")
CronMapper cronMapper;
/**
* 执行定时任务.
*/
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(
() -> System.out.println("执行动态定时任务: " + LocalDateTime.now().toLocalTime()),
triggerContext -> {
String cron = cronMapper.getCron();
if (StringUtils.isEmpty(cron)) {
}
return new CronTrigger(cron).nextExecutionTime(triggerContext);
}
);
}
}
测试定时任务
配置完成后,我们启动项目,发现定时任务按照设定的每秒执行输出,而如果我们修改数据库中cron字段对应的值为'0/5 * * ? * ?'时,定时任务的规则自动发生了变化。如果最终修改的值不符合cron表达式规范,那么定时器类会报错停止执行。