动态控制Cron定时任务
针对应用中需求的大量定时任务,实现灵活有效的控制,自己已经在项目中,希望对小伙伴们有用!

废话不多直接教你怎么拿来就能用
Spring提供的CronTask定时任务注册类
@Component
public class CronTaskRegistrar implements DisposableBean {
/**
* 缓存
*/
private final Map < Runnable, ScheduledTask > scheduledTasks = new ConcurrentHashMap<>(16);
@Autowired
private TaskScheduler taskScheduler;
/**
* 添加一个定时任务 其核心就是靠spring提供的 CronTask 类来实现
*
* @param task
* @param cronExpression
*/
public void addCronTask(Runnable task, String cronExpression) {
addCronTask(new CronTask(task, cronExpression));
}
public void addCronTask(CronTask cronTask) {
if (cronTask != null) {
Runnable task = cronTask.getRunnable();
if (this.scheduledTasks.containsKey(task)) {
removeCronTask(task);
}
this.scheduledTasks.put(task, scheduleCronTask(cronTask));
}
}
public void removeCronTask(Runnable task) {
ScheduledTask scheduledTask = this.scheduledTasks.remove(task);
if (scheduledTask != null)
scheduledTask.cancel();
}
public ScheduledTask scheduleCronTask(CronTask cronTask) {
ScheduledTask scheduledTask = new ScheduledTask();
scheduledTask.future = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
return scheduledTask;
}
@Override
public void destroy() {
for (ScheduledTask task : this.scheduledTasks.values()) {
task.cancel();
}
this.scheduledTasks.clear();
}
}
定时任务多线程配置类:
@EnableScheduling // 开启定时任务
@EnableAsync // EnableAsync注解的意思是可以异步执行,就是开启多线程的意思
public class SchedulingConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
// 定时任务执行线程池核心线程数
taskScheduler.setPoolSize(100);
taskScheduler.setRemoveOnCancelPolicy(true);
// 线程池任务调度
taskScheduler.setThreadNamePrefix("MyTaskSchedulerThreadPool-");
return taskScheduler;
}
}
定时任务运行类
private static final Logger logger = LoggerFactory.getLogger(SchedulingRunnable.class);
private String beanName;
private String methodName;
private Integer frequency;
private Object[] params;
public SchedulingRunnable(String beanName, String methodName, Integer frequency) {
this(beanName, methodName, frequency, null);
}
public SchedulingRunnable(String beanName, String methodName, Integer frequency, Object... params) {
this.beanName = beanName;
this.methodName = methodName;
this.frequency = frequency;
this.params = params;
}
@Override
public void run() {
// logger.info("定时任务开始执行 - bean:{},方法:{},参数:{}", beanName, methodName, params);
long startTime = System.currentTimeMillis();
try {
Object target = SpringContextUtils.getBean(beanName);
Method method = null;
if (null != params && params.length > 0) {
Class < ? >[] paramCls = new Class[params.length];
for (int i = 0; i < params.length; i++) {
paramCls[i] = params[i].getClass();
}
method = target.getClass().getDeclaredMethod(methodName, paramCls);
}
else {
method = target.getClass().getDeclaredMethod(methodName);
}
ReflectionUtils.makeAccessible(method);
if (null != params && params.length > 0) {
method.invoke(target, params);
}
else {
method.invoke(target);
}
}
catch (Exception ex) {
ex.printStackTrace();
logger.error(String.format("定时任务执行异常 - bean:%s,方法:%s ", beanName, methodName), ex);
}
long times = System.currentTimeMillis() - startTime;
long frequencyTime = (System.currentTimeMillis() - startTime) / 1000;// 执行时间
if ((int) frequencyTime > frequency) {// 如果执行时间大于设置的时间
logger.info("定时任务执行结束 - bean:{},方法:{},参数:{},耗时:{} 毫秒,预设时间数据分析:{}", beanName, methodName, params, times,
"超时");
}
// else {
// logger.info("定时任务执行结束 - bean:{},方法:{},参数:{},耗时:{} 毫秒,预设时间数据分析:{}", beanName, methodName, params, times,
// "正常");
// }
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (o == null || getClass() != o.getClass())
return false;
SchedulingRunnable that = (SchedulingRunnable) o;
if (params == null) {
return beanName.equals(that.beanName) && methodName.equals(that.methodName) && that.params == null;
}
return beanName.equals(that.beanName) && methodName.equals(that.methodName) && params.equals(that.params);
}
@Override
public int hashCode() {
if (params == null) {
return Objects.hash(beanName, methodName);
}
return Objects.hash(beanName, methodName, params);
}
}
这个也需要,差点忘了
@Component
public class SpringContextUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
SpringContextUtils.applicationContext = applicationContext;
}
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
}
定时任务控制器
public class SysJobRunner implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(SysJobRunner.class);
@Value("${scheduled.enable}")
private String scheduledEnable;
@Autowired
private SysJobPOMapper sysJobMapper;
@Autowired
private CronTaskRegistrar cronTaskRegistrar;
@Override
public void run(String... args) {
// 如果是真的就不执行了
if (Boolean.parseBoolean(scheduledEnable))
return;
// 初始加载数据库里状态为正常的定时任务
List < SysJobPO > jobList = sysJobMapper.getSysJobListByStatus(SysJobStatus.NORMAL.index());
if (!CollectionUtils.isEmpty(jobList)) {
for (SysJobPO job : jobList) {
SchedulingRunnable task = new SchedulingRunnable(job.getBeanName(), job.getMethodName(),
job.getFrequency());
cronTaskRegistrar.addCronTask(task, job.getCronExpression());
}
logger.info("定时任务已加载完毕...");
}
}
}
状态控制器
public enum SysJobStatus {
NORMAL("正常", 1), SUSPEND("暂停", 0);
private String desc;
private Integer index;
private SysJobStatus(String desc, Integer index) {
this.desc = desc;
this.index = index;
}
public String desc() {
return this.desc;
}
public Integer index() {
return this.index;
}
}
Controller层控制类
public class TaskController {
@Autowired
private SysJobPOMapper sysJobMapper;
@Autowired
private CronTaskRegistrar cronTaskRegistrar;
@PostMapping("/addTask")
public String addTask(SysJobPO sysJob) {
sysJob.setCreateTime(new Date());
boolean success = sysJobMapper.addSysJob(sysJob);
if (!success)
return "新增失败";
else {
if (sysJob.getJobStatus().equals(SysJobStatus.NORMAL.index())) {
SchedulingRunnable task = new SchedulingRunnable(sysJob.getBeanName(), sysJob.getMethodName(),
sysJob.getFrequency());
// 注册定时任务
cronTaskRegistrar.addCronTask(task, sysJob.getCronExpression());
}
}
return "SUCCESS";
}
/**
* 修改定时任务(只能先停,修改状态然后再开启)
*
* @param sysJob
* @return
*/
@PostMapping("/updateTask")
public String updateTaskJob(SysJobPO sysJob) {
SysJobPO existJob = sysJobMapper.findTaskJobByJobId(sysJob.getJobId());
sysJob.setUpdateTime(new Date());
boolean success = sysJobMapper.updateTaskJob(sysJob);
if (!success) {
return "修改失败";
}
else {
// 1. 先删除原来的定时任务(Map缓存)(获取到的参数)
if (existJob.getJobStatus().equals(SysJobStatus.NORMAL.index())) {
SchedulingRunnable task = new SchedulingRunnable(existJob.getBeanName(), existJob.getMethodName(),
existJob.getFrequency());
cronTaskRegistrar.removeCronTask(task);
}
// 2. 新增定时任务(放到Map缓存中)(穿进来的参数)
if (sysJob.getJobStatus().equals(SysJobStatus.NORMAL.index())) {
SchedulingRunnable task = new SchedulingRunnable(sysJob.getBeanName(), sysJob.getMethodName(),
existJob.getFrequency());
cronTaskRegistrar.addCronTask(task, sysJob.getCronExpression());
}
}
return "SUCCESS";
}
/**
* 删除某个定时任务
*/
@GetMapping("/deleteTask")
public String deleteTask(Integer jobId) {
SysJobPO existJob = sysJobMapper.findTaskJobByJobId(jobId);
boolean success = sysJobMapper.deleteTaskJobByJobId(jobId);
if (!success)
return "删除失败";
else {
if (existJob.getJobStatus().equals(SysJobStatus.NORMAL.index())) {
SchedulingRunnable task = new SchedulingRunnable(existJob.getBeanName(), existJob.getMethodName(),
existJob.getFrequency());
// 删除定时任务
cronTaskRegistrar.removeCronTask(task);
}
}
return "SUCCESS";
}
/**
* 启,停定时任务的状态切换
*/
@GetMapping("/trigger")
public String triggerTaskJob(Integer jobId) {
SysJobPO existJob = sysJobMapper.findTaskJobByJobId(jobId);
// 1.如果原先是启动状态 ,那么就停止吧(从Map缓存中删除, 并将表中状态置为0)
if (existJob.getJobStatus().equals(SysJobStatus.NORMAL.index())) {
SchedulingRunnable task = new SchedulingRunnable(existJob.getBeanName(), existJob.getMethodName(),
existJob.getFrequency());
cronTaskRegistrar.removeCronTask(task);
existJob.setJobStatus(0);
sysJobMapper.updateTaskJob(existJob);
}
else {
SchedulingRunnable task = new SchedulingRunnable(existJob.getBeanName(), existJob.getMethodName(),
existJob.getFrequency());
cronTaskRegistrar.addCronTask(task, existJob.getCronExpression());
existJob.setJobStatus(1);
sysJobMapper.updateTaskJob(existJob);
}
return "SUCCESS";
}
}
取消定时任务
public final class ScheduledTask {
@SuppressWarnings("rawtypes")
volatile ScheduledFuture future;
@SuppressWarnings("rawtypes")
public void cancel() {
ScheduledFuture future = this.future;
if (future != null) {
future.cancel(true);
}
}
}
实体类也扔一下吧,因为有的小伙伴特别懒
@Entity
@Table(name = "sys_job_po")
public class SysJobPO implements java.io.Serializable {
private static final long serialVersionUID = 4769112479059268023L;
/**
* 任务ID
*/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY) // 自增长使用
private Integer jobId;
/**
* bean名称 , 如示例中的: demoTask
*/
private String beanName;
/**
* 方法名称
*/
private String methodName;
/**
* cron表达式
*/
private String cronExpression;
/**
* 状态(1正常 0暂停)
*/
private Integer jobStatus;
/**
* 备注
*/
private String remark;
/**
* 创建时间
*/
private Date createTime;
拿来主义盛行,给你喂到嘴里
public interface SysJobPOMapper {
boolean deleteTaskJobByJobId(Integer jobId);
boolean addSysJob(SysJobPO record);
SysJobPO findTaskJobByJobId(Integer jobId);
List < SysJobPO > getSysJobListByStatus(Integer jobStatus);
List < SysJobPO > triggerTaskBeanName(String beanName);
boolean updateTaskJob(SysJobPO record);
}
备注:
如果你不懂,可以留言,或者代码不全,也可以留言或者私信我
本文介绍如何在Spring项目中实现动态控制Cron定时任务,包括添加、删除和更新任务。通过自定义的`CronTaskRegistrar`类,结合`TaskScheduler`和`@EnableScheduling`,实现了对定时任务的灵活管理。同时提供了`SchedulingRunnable`类用于执行具体的任务,以及`SpringContextUtils`帮助类获取Bean。此外,还展示了如何通过Controller层接口进行任务的增删改查操作,以及状态切换。
1024

被折叠的 条评论
为什么被折叠?



