条件触发定时任务
在springboot项目中,如果要使用定时任务,一般都会在controller的接口上加**@Scheduled**注解,并在其注解里写上cron表达式,注意启动类一定要加@EnableScheduling注解来开启定时任务。但是这种方式不灵活,一旦项目启动后就不能更改。接下来给大家介绍另一种条件触发定时任务:
很好理解,就是在达到某种条件的时候,自动开启和停止定时任务
首先定时的任务类要实现Runnable接口
@Component
@Slf4j
public class FirstTask implements Runnable {
private ScheduledFutureUtil scheduledFutureUtil = (ScheduledFutureUtil) SpringApplicationContextUtil.getBean("ScheduledFutureUtil");
private Integer num = 0;
@Override
public void run() {
num++;
System.out.println("这是第一个定时任务:" + num);
if (num == 4) {
//停止第一个定时任务
scheduledFutureUtil.endJob("com.song.task.FirstTask");
//开启第二个定时任务
SecondTask secondTask = new SecondTask();
String corn = "0/3 * * * * ?";
scheduledFutureUtil.startJob(secondTask,corn);
log.info("第二个任务已开启");
}
}
}
public class SecondTask implements Runnable {
private ScheduledFutureUtil scheduledFutureUtil = (ScheduledFutureUtil) SpringApplicationContextUtil.getBean("ScheduledFutureUtil");
private Integer num = 0;
@Override
public void run() {
num++;
System.out.println("这是第二个定时任务:"+num);
if(num == 4){
//停止第二个定时任务
scheduledFutureUtil.endJob("com.song.task.SecondTask");
}
}
}
上面是提前写好的两个runnable任务,再然后得借助ThreadPoolTaskScheduler这个类,可以通过configuration和Bean两个注解将ThreadPoolTaskScheduler注入到spring得容器里,方便拿取
@Configuration
public class ScheduledConfig {
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(3);
threadPoolTaskScheduler.setRemoveOnCancelPolicy(true);
return threadPoolTaskScheduler;
}
}
下面是封装好的一个开启和停止定时任务的一个工具
public class ScheduledFutureUtil {
//存储任务执行的包装类
public static HashMap<String, ScheduledFutureHolder> scheduleMap = new HashMap<>();
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
public void startJob(Runnable runnable, String cron) {
//将任务交给任务调度器执行
ScheduledFuture<?> schedule = threadPoolTaskScheduler.schedule(runnable, new CronTrigger(cron));
//将任务包装成ScheduledFutureHolder
ScheduledFutureHolder scheduledFutureHolder = new ScheduledFutureHolder();
scheduledFutureHolder.setScheduledFuture(schedule);
scheduledFutureHolder.setRunnableClass(runnable.getClass());
scheduledFutureHolder.setCorn(cron);
scheduleMap.put(scheduledFutureHolder.getRunnableClass().getName(), scheduledFutureHolder);
}
public void endJob(String className){
if(ScheduledFutureUtil.scheduleMap.containsKey(className)){//如果包含这个任务
ScheduledFuture<?> scheduledFuture = ScheduledFutureUtil.scheduleMap.get(className).getScheduledFuture();
if(scheduledFuture!=null){
scheduledFuture.cancel(true);
log.info("{}任务已停止",className);
}
}
}
}
通过上面的方法可以看出,开启定时任务,其实最主要的就是,将任务交给任务调度器执行,也就是执行ThreadPoolTaskScheduler的schedule方法,然后返回一个ScheduledFuture类型的参数,然后将该参数和任务包装成ScheduledFutureHolder,最后将scheduledFutureHolder放入一个map集合里。key是定时任务类名,value是ScheduledFutureHolder类
停止定时任务,就是在该map集合里通过类名找到对应的定时任务,然后执行ScheduledFuture的cancel方法
下面是封装好的ScheduledFutureHolder
/**
* 任务执行的包装类
*/
public class ScheduledFutureHolder {
private ScheduledFuture<?> scheduledFuture;
private Class<? extends Runnable> runnableClass;
private String corn;
public ScheduledFuture<?> getScheduledFuture() {
return scheduledFuture;
}
public void setScheduledFuture(ScheduledFuture<?> scheduledFuture) {
this.scheduledFuture = scheduledFuture;
}
public Class<? extends Runnable> getRunnableClass() {
return runnableClass;
}
public void setRunnableClass(Class<? extends Runnable> runnableClass) {
this.runnableClass = runnableClass;
}
public String getCorn() {
return corn;
}
public void setCorn(String corn) {
this.corn = corn;
}
@Override
public String toString() {
return "ScheduledFutureHolder{" +
"scheduledFuture=" + scheduledFuture +
", runnableClass=" + runnableClass +
", corn='" + corn + '\'' +
'}';
}
}