1.启动类打开
@EnableScheduling 注解
2. 创建定时任务线程池配置
@Configuration
public class SchedulingConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
// 定时任务执行线程池核心线程数
taskScheduler.setPoolSize(6);
taskScheduler.setRemoveOnCancelPolicy(true);
taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");
return taskScheduler;
}
}
3.创建数据库表,用来保存定时任务详情,调度等信息
@Data
@EqualsAndHashCode(callSuper = false)
public class TimerTask implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 任务id
*/
@TableId
private Long taskId;
/**
* 任务表达式
*/
private String taskCron;
/**
* 任务描述
*/
private String taskDesc;
/**
* 任务类名
*/
private String beanName;
/**
* 任务名称
*/
private String methodName;
/**
* 任务参数
*/
private String methodParams;
/**
* 任务状态 0开启 1关闭
*/
private int taskEnable;
/**
* 创建时间
*/
private Date createTime;
/**
* 修改时间
*/
private Date modifyTime;
}
4.项目启动后初始化定时任务,(tasks就是保存在数据库表里的所有定时任务)
@Slf4j
@Component
public class SchedulingRunnable implements CommandLineRunner {
@Autowired
private TimerTaskService taskService;
@Override
public void run(String... args) {
List<TimerTask> tasks = taskService.list();
for (TimerTask task : tasks) {
if (task.getTaskEnable() == 0) {
taskService.scheduleTask(task);
}
}
log.info("定时任务初始化成功!!!");
}
}
5.TimerTaskService ,实现定时任务的添加,取消等业务
public interface TimerTaskService extends IService<TimerTask> {
void addTask(TimerTask task);
void updateTask(TimerTask task);
void delTask(Long taskId);
void scheduleTask(TimerTask task);
}
package com.ly.mk.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ly.mk.entity.TimerTask;
import com.ly.mk.mapper.TimerTaskMapper;
import com.ly.mk.service.TimerTaskService;
import com.ly.mk.util.SpringContextUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
@Slf4j
@Service
public class TimerTaskServiceImpl extends ServiceImpl<TimerTaskMapper, TimerTask> implements TimerTaskService {
@Autowired
private TaskScheduler taskScheduler;
private Map<Long, ScheduledFuture<?>> scheduledFutureMap = new ConcurrentHashMap<>();
@Override
@Transactional(rollbackFor = Exception.class)
public void addTask(TimerTask task) {
task.setCreateTime(new Date());
this.save(task);
if (task.getTaskEnable() == 0) {
scheduleTask(task);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void updateTask(TimerTask task) {
//更新数据库
task.setModifyTime(new Date());
this.updateById(task);
//先删除
cancelTask(task.getTaskId());
//开启定时任务
if (task.getTaskEnable() == 0) {
scheduleTask(task);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void delTask(Long taskId) {
this.removeById(taskId);
cancelTask(taskId);
}
private void cancelTask(Long taskId) {
ScheduledFuture<?> scheduledFuture = scheduledFutureMap.get(taskId);
if (Objects.nonNull(scheduledFuture))
scheduledFuture.cancel(true);
// 如果任务取消需要消耗点时间
boolean cancelled = scheduledFuture.isCancelled();
while (!cancelled) {
scheduledFuture.cancel(true);
}
// 最后从队列中删除
scheduledFutureMap.remove(taskId);
}
//定时任务添加到任务队列
public void scheduleTask(TimerTask task) {
scheduledFutureMap.put(task.getTaskId(), taskScheduler.schedule(createRunnableTask(task), new CronTrigger(task.getTaskCron())));
}
private Runnable createRunnableTask(TimerTask task) {
return () -> {
Object target = SpringContextUtils.getBean(lowerFirstCapse(task.getBeanName()));
Method method;
String methodName = task.getMethodName();
String methodParams = task.getMethodParams();
try {
if (StringUtils.isNotBlank(methodName)) {
method = target.getClass().getDeclaredMethod(methodName, String.class);
} else {
method = target.getClass().getDeclaredMethod(methodName);
}
ReflectionUtils.makeAccessible(method);
if (StringUtils.isNotBlank(methodParams)) {
method.invoke(target, methodParams);
} else {
method.invoke(target);
}
} catch (Exception e) {
e.printStackTrace();
log.error(String.format("定时任务执行异常 - bean:%s,方法:%s,参数:%s ", task.getBeanName(), methodName, methodParams), e);
}
};
}
/**
* 转换首字母小写
*
* @param str
* @return
*/
public static String lowerFirstCapse(String str) {
char[] chars = str.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
}
6.根据自己的业务需求创建自己的定时任务实现类,实现具体逻辑