准备工作
动态配置定时任务,使用SpringBoot内置的就行,在搭建好SpringBoot框架后不需要再引入其他依赖
所涉及到的类
(1) ScheduleModel类: 动态任务数据库所映射的实体类,动态更改cron表达式
(2) ScheduleConfig类: 定时任务的配置类,需要实现 SchedulingConfigurer接口
(3) ScheduledTask类 : 定时任务,所执行方法类,实现Runable接口
(4) SpringScheduledCronRepository类: 相当于一个工具类,用来添加删除修改定时任务
一、编写ScheduleModel类
先创建数据库表, 以及映射的实体类,下面我只展示实体类的字段,数据库请自建
public class ScheduledModel {
/**
* 主键
*/
private Integer id;
/**
* 定时任务的cron表达式
*/
private String cronExpression;
/**
* 定时任务的状态(主要是判断当前定时任务是否被弃用,作为取消的依据)
*/
private Integer state;
}
CREATE TABLE schedule_model(
id int PRIMARY KEY auto_increment COMMENT '主键',
cron_expression VARCHAR(50) NOT NULL COMMENT 'cron表达式',
state int NOT NULL DEFAULT 1 COMMENT '状态'
)
二、编写ScheduledTask类
这里先编写定时任务执行方法类,这里我就没写过多东西,如果需要传参,需要查数据库,自己构造就好了,根据自己的业务需求来
public class ScheduledTask implements Runnable {
@Override
public void run() {
System.out.println("我是定时任务哦" + new Date());
}
}
三、编写SpringScheduledCronRepository类
这个类相当于一个工具类或者说是service类,主要是定义了动态任务初始化,增加,取消,查询方法
import com.laohe.entity.SpringScheduledCron;
import lombok.SneakyThrows;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
@Component
@Configuration
public class SpringScheduledCronRepository {
/**
* 定时任务的线程池
*/
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
/**
* ScheduleModel实体类的Mapper
*/
@Autowired
private ScheduledModelMapper scheduledModelMapper;
/**
* 存放所以定时任务实体类的Map
*/
private static Map<Integer, ScheduledModel> scheduledModelMap = new ConcurrentHashMap<>();
/**
* 存放定时任务的Map
*/
private static Map<Integer, ScheduledFuture<?>> scheduledFutureMap = new ConcurrentHashMap<>();
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
return new ThreadPoolTaskScheduler();
}
/**
* 初始化任务
*/
public void initScheduledTask() {
//1.查询数据库中所有的定时任务
List<ScheduledModel> scheduledModels = scheduledModelMapper.selectAll();
scheduledModels.forEach(scheduledModel -> {
addTask(scheduledModel);
});
}
/**
* 增加任务
*/
public void addTask(ScheduledModel scheduledModel) {
//1.先判定该定时任务的状态
if (scheduledModel.getState() == 0) {
return;
}
//2.增加定时任务,map中是否存在了如果存在 移除取消
if (scheduledModelMap.containsKey(scheduledModel.getId())) {
cancelTask(scheduledModel.getId());
}
// 定时任务线程方法可以传入参数 根据自己需求去定义吧
// 如果定时任务线程方法也想动态更新 这里就不使用new的方式去创建对象
// 使用 ApplicationContext去获取
ScheduledTask task = new ScheduledTask();
//3.添加定时任务
ScheduledFuture<?> schedule = threadPoolTaskScheduler.schedule(task, triggerContext -> {
// 通过当前ID查询到定时任务信息
ScheduledModel scheduled = scheduledModelMapper.selectById(scheduledModel.getId());
// nextExecutionTime指向的是下一次执行的时间
//这里每次配置就会查询数据库中的cron表达式 我们只需要更新数据库就可以了 ,如果觉得Mysql慢 也可以考虑使用Redis
return new CronTrigger(scheduled.getCronExpression()).nextExecutionTime(triggerContext);
});
scheduledFutureMap.put(scheduledModel.getId(),schedule);
scheduledModelMap.put(scheduledModel.getId(),scheduledModel);
}
/**
* 取消定时任务
*/
public void cancelTask(Integer id) {
if (scheduledFutureMap.containsKey(id)) {
ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get(id);
scheduledFuture.cancel(true);
scheduledFutureMap.remove(id);
scheduledModelMap.remove(id);
}
}
/**
* 查询现在所有的定时任务
*/
public String findAllTask() {
return scheduledModelMap.toString();
}
}
四、编写ScheduleConfig类
这里开始编写配置类,虽然配置类是第一个执行,但是需要调用前面的方法,所以就按调用顺序编写的这篇文章,更方便理解
import lombok.SneakyThrows;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledThreadPoolExecutor;
@Configuration
@EnableScheduling
public class ScheduledConfig implements SchedulingConfigurer {
@Autowired
private SpringScheduledCronRepository repository;
@Autowired
private ApplicationContext context;
@SneakyThrows
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
// 初始化定时任务
repository.initScheduledTask();
// 其实这里也可以使用scheduledTaskRegistrar去添加任务的
// 但是这样动态增加的时候,还是需要使用SpringScheduledCronRepository的add方法
// 而且取消任务不方便 就放弃了在这里配置
// 调用scheduledTaskRegistrar的方法就可以了 也很方便 看实际需求吧
}
@Bean
public Executor taskExecutor() {
return new ScheduledThreadPoolExecutor(10);
}
}
五、Controller层编写
@RestController
@RequestMapping
public class TaskController {
@Autowired
private SpringScheduledCronRepository cronRepository;
/**
* 查询所有
*/
@RequestMapping("findAll")
public String findAll() {
return cronRepository.findAllTask();
}
/**
* 增加
*/
@RequestMapping("addTask")
public void addTask(@RequestBody ScheduledModel scheduledModel) {
cronRepository.addTask(scheduledModel);
}
/**
* 取消
*/
@RequestMapping("cancel")
public void cancel(Integer id) {
cronRepository.cancelTask(id);
}
}
六、运行结果
数据库初始化数据有两条
项目启动运行结果
依次取消这两条数据,测试取消是否成功(如下图两个都取消后并无输出了)
再增加一个定时任务(再看增加之后又有定时任务了)
总结
上面就是配置定时任务的大概Demo,代码的编写还得按照自己的业务去实现,上面代码编写不一定适合你们的业务