springboot项目在启动时自动添加定时任务
1、springboot项目的启动器类添加注解
@EnableScheduling
2、动态添加定时任务
需求一:简单实现启动项目时自动添加定时任务,定时时间从数据库查
添加配置类
新建config包,包下新建ScheduleTask
类实现SchedulingConfigurer
接口,代码如下:
package org.springxxx.modules.xxx.config;
import java.util.List;
import org.springblade.modules.datatrans.entity.DataResource;
import org.springblade.modules.datatrans.mapper.DataResourceMapper;
import org.springblade.modules.datatrans.service.IDataResourceService;
import org.springblade.modules.datatrans.utils.CronExpParser;
import org.springframework.beans.factory.annotation.Autowired;
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 org.springframework.scheduling.support.CronTrigger;
import com.aliyuncs.utils.StringUtils;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
@Configuration // 1.主要用于标记配置类,兼备Component的效果。
@EnableScheduling // 2.开启定时任务
public class ScheduleTask implements SchedulingConfigurer {
@Autowired
DataResourceMapper dataResourceMapper;
@Autowired
IDataResourceService dataResourceService;
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
QueryWrapper<DataResource> drWrapper = new QueryWrapper<>();
List<DataResource> dataResourceList = dataResourceMapper.selectList(drWrapper.eq("deleted", 0));
for (DataResource dataResource : dataResourceList) {
// 2.1 从数据库获取执行周期
String cron = dataResource.getExecuteCron();
// 2.2 合法性校验. 正确的cron表达式+数据资源可访问状态为正常
if (!StringUtils.isEmpty(cron) && dataResource.getAccessibleState().equals("1")) {
System.out.println("添加动态定时任务: " + dataResource.getDataName() + ","
+ CronExpParser.translateToChinese(cron) + "执行一次");
taskRegistrar.addTriggerTask(
// 1.添加任务内容(Runnable)
() -> {
System.out.println("执行动态定时任务: " + dataResource.getDataName());
dataResourceService.refreshByTime(dataResource);
},
// 2.设置执行周期(Trigger)
triggerContext -> {
// 2.3 返回执行周期(Date)
return new CronTrigger(cron).nextExecutionTime(triggerContext);
});
}
}
}
}
需求二:动态实现定时任务的启动、指定某个停止、全部停止等
1、新建配置类:实现在启动springboot时自动开始周期任务
package com.waterlog.system.config;
import com.alibaba.fastjson.JSONObject;
import com.waterlog.system.entity.SensorConnInfo;
import com.waterlog.system.service.SensorConnInfoService;
import com.waterlog.system.task.SensorTask;
import com.waterlog.system.task.TaskBase;
import org.springframework.beans.factory.annotation.Autowired;
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.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
@Configuration
@EnableScheduling // 2.开启定时任务
public class ScheduleTaskConfig implements SchedulingConfigurer {
// 用来存入线程执行情况, 方便于停止定时任务时使用
public static ConcurrentHashMap<String, ScheduledFuture> cache = new ConcurrentHashMap<String, ScheduledFuture>();
@Autowired
SensorConnInfoService sensorConnInfoService;
@Autowired
SensorTask sensorTask;
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler() {
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(5);
threadPoolTaskScheduler.setThreadNamePrefix("sensorExecutor-"); // 线程名称
// threadPoolTaskScheduler.setAwaitTerminationSeconds(600); // 等待时长设置为十分钟
threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true); // 调度器shutdown被调用时等待当前被调度的任务完成
threadPoolTaskScheduler.setRemoveOnCancelPolicy(true); //设置取消策略,我们可以立即将任务从工作队列中移除,而不是等待预定的持续时间,直到任务从工作队列中移除。
return threadPoolTaskScheduler;
}
@Override
public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
// 调用垂天传感器信息中的定时任务
List<JSONObject> taskJsons = sensorConnInfoService.exeNativeSql("select id,name,exec_plan_cron,conn_id,save_record from sensor_info where " +
"del_status = '0'");
ArrayList<TaskBase> sensorCtkjs = new ArrayList<>();
for (JSONObject taskJson : taskJsons) {
String id = taskJson.getString("id");
String cron = taskJson.getString("exec_plan_cron");
String connId = taskJson.getString("conn_id");
Boolean saveRecord = (taskJson.getInteger("save_record") == 1);
TaskBase taskBase = new TaskBase(id, cron) {
@Override
public void run() {
SensorConnInfo connInfo = sensorConnInfoService.selectById(connId);
sensorConnInfoService.verify(connInfo.getUrl(), connInfo.getMethod(), connInfo.getParams(), connInfo.getSensorType(),
connInfo.getDeviceType(), saveRecord, id);
}
};
sensorCtkjs.add(taskBase);
}
//TODO 调用其他传感器信息中的定时任务 往sensorCtkjs里面加
sensorTask.startCron(sensorCtkjs);
}
}
2、新建基类抽象类,每个任务类必须继承此基类
package com.waterlog.system.task;
public abstract class TaskBase implements Runnable {
private String name; // 任务名字
private String cron; // 触发条件
public TaskBase() {
}
public TaskBase(String name, String cron) {
this.name = name;
this.cron = cron;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getCron() {
return cron;
}
public void setCron(String cron) {
this.cron = cron;
}
}
3、封装任务管理工具类
package com.waterlog.system.task;
import com.waterlog.system.config.ScheduleTaskConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import java.util.List;
import java.util.concurrent.ScheduledFuture;
@Component
public class SensorTask {
private static final Logger logger = LoggerFactory.getLogger(SensorTask.class);
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;// 注入线程池任务调度类
public void startCron(List<? extends TaskBase> ctkjTasks) {
ctkjTasks.forEach(sensorCtkj -> {
// 开始执行调度
ScheduledFuture scheduledFuture = threadPoolTaskScheduler.schedule(sensorCtkj, new CronTrigger(sensorCtkj.getCron()));
// 将 scheduledFuture 保存下来用于停止任务使用
ScheduleTaskConfig.cache.put(sensorCtkj.getName(), scheduledFuture);
logger.info("添加了定时任务:{},执行周期为:{}", sensorCtkj.getName(), sensorCtkj.getCron());
});
}
public void stop(String taskId) {
if (ScheduleTaskConfig.cache.isEmpty()) return;
if (ScheduleTaskConfig.cache.get(taskId) == null) return;
ScheduledFuture scheduledFuture = ScheduleTaskConfig.cache.get(taskId);
if (scheduledFuture != null) {
scheduledFuture.cancel(true); // 这里需要使用指定的 scheduledFuture 来停止当前的线程
ScheduleTaskConfig.cache.remove(taskId); // 移除缓存
logger.info("移除了定时任务:{}", taskId);
}
}
public void stopAll() {
if (ScheduleTaskConfig.cache.isEmpty()) return;
ScheduleTaskConfig.cache.values().forEach(scheduledFuture -> scheduledFuture.cancel(true));
logger.info("移除了所有定时任务");
}
}
4、实现需要定时执行的具体业务,并传入工具类中进行启动
SensorConnInfo connInfo = sensorConnInfoService.selectById(sensorInfo.getConnId());
String taskId = sensorInfo.getId();
sensorTask.stop(taskId);//先停掉以前的周期任务再启动新的
TaskBase taskBase = new TaskBase(taskId, sensorInfo.getExecPlanCron()) {
@Override
public void run() {
sensorConnInfoService.verify(connInfo.getUrl(), connInfo.getMethod(), connInfo.getParams(), connInfo.getSensorType(),
connInfo.getDeviceType(), sensorInfo.getSaveRecord() == 1, sensorInfo.getId());
}
};
List<TaskBase> taskBases = new ArrayList<TaskBase>(1);
taskBases.add(taskBase);
sensorTask.startCron(taskBases);
3、静态添加定时任务
需求:定时执行某个方法,定时时间写死
在方法上面加
@Scheduled(cron = "0 0/30 * * * ? ")
public static void checkRsa() {
System.out.println("每三十分钟执行一次")
}
4、cron表达式在线生成
5、如果不用cron表达式,可以直接使用毫秒
//initialDelay:当任务启动后多久开始执行此方法,fixedDelay:执行频率为多少
@Scheduled(initialDelay = 1000,fixedDelay = 1000*10)
public static void checkRsa() {
System.out.println("每十秒钟执行一次")
}