SpringBoot 创建定时任务
创建定时任务非常简单,主要有两种创建方式:一、基于注解(@Scheduled) 二、基于接口(SchedulingConfigurer). 前者相信大家都很熟悉,但是实际使用中我们往往想从数据库中读取指定时间来动态执行定时任务,这时候基于接口的定时任务就大派用场了。
静态定时任务(基于注解)
基于注解来创建定时任务非常简单,只需几行代码便可完成。
@Configuration
public class SimpleScheduleConfig {
//3.添加定时任务
@Scheduled(cron = "0/5 * * * * ?")
private void configureTasks() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.err.println("执行定时任务1: " + simpleDateFormat.format(new Date()));
}
}
执行定时任务1: 2019-02-07 00:45:00
执行定时任务1: 2019-02-07 00:45:05
执行定时任务1: 2019-02-07 00:45:10
执行定时任务1: 2019-02-07 00:45:15
@Scheduled 除了支持灵活的参数表达式cron之外,还支持简单的延时操作,例如 fixedDelay ,fixedRate 填写相应的毫秒数即可。
@Configuration
public class SimpleScheduleConfig {
//3.添加定时任务
@Scheduled(fixedRate = 3000)
private void configureTasks() {
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
System.err.println("执行定时任务1: " + simpleDateFormat.format(new Date()));
}
}
执行定时任务1: 2019-02-07 00:46:16
执行定时任务1: 2019-02-07 00:46:19
执行定时任务1: 2019-02-07 00:46:22
使用Scheduled 确实很方便,但缺点是当我们调整了执行周期的时候,需要重启应用才能生效,这多少有些不方便。为了达到实时生效的效果,可以使用接口来完成定时任务。
动态定时任务(基于接口)
为了演示效果,这里选用 Mysql数据库 和 Mybatis 来查询和调整定时任务的执行周期,然后观察定时任务的执行情况。
引入依赖:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.10</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.9</version>
</dependency>
</dependencies>
添加数据库记录:
DROP DATABASE IF EXISTS `socks`;
CREATE DATABASE `socks`;
USE `SOCKS`;
DROP TABLE IF EXISTS `cron`;
CREATE TABLE `cron` (
`cron_id` varchar(30),
`cron` varchar(30)
);
INSERT INTO `cron` VALUES ('1', '0/5 * * * * ?');
application.yml 配置如下:
spring:
datasource:
druid:
db-type: com.alibaba.druid.pool.DruidDataSource
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/socks?useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=UTC
username: root
password: 1111
initial-size: 5
max-active: 20
min-idle: 5
max-wait: 60000
server:
port: 8088
创建定时器:
@Configuration
@EnableScheduling
public class CompleteScheduleConfig implements SchedulingConfigurer {
@Mapper
public interface CronMapper{
@Select("select cron from cron limit 1")
String getCron();
}
@Autowired
@SuppressWarnings("all")
CronMapper cronMapper;
/**
* 执行任务
*/
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
taskRegistrar.addTriggerTask(
//1.添加任务内容(Runnable)
() -> System.out.println("执行定时任务: " + LocalDateTime.now().toLocalTime()),
//2.设置执行周期(Trigger)
triggerContext -> {
//2.1 从数据库获取执行周期
String cron = cronMapper.getCron();
//2.2 合法性校验.
if (StringUtils.isEmpty(cron)) {
// Omitted Code ..
}
//2.3 返回执行周期(Date)
return new CronTrigger(cron).nextExecutionTime(triggerContext);
}
);
}
}
查看控制台,打印时间是我们预期的每5秒一次,然后打开Navicat ,将执行周期修改为每1秒执行一次,发现执行周期已经改变,并且不需要我们重启应用,十分方便。
执行定时任务: 00:51:23.001
执行定时任务: 00:51:24.001
执行定时任务: 00:51:25.001
执行定时任务: 00:51:26.001
执行定时任务: 00:51:27.002
执行定时任务: 00:51:28.003
执行定时任务: 00:51:29.001