一般情况下定时任务的使用常见的两个组件:xxl-job和quartz,这两种需要引用相应的依赖,针对对定时任务较为复杂和依赖性较高的系统
但是如果项目中使用定时任务的场景不多,避免项目过于臃肿和复杂,但要求可配置、可删除、可启停用的
定时任务的必要字段
TASK_NAME: 定时任务名称;
TASK_CRON:定时任务执行频率,cron表达式
TASK_BEAN: 执行定时任务的Bean名称
TASK_MOTHOD: 执行定时任务的方法名
一、创建线程池并设置参数
ThreadPoolTaskScheduler:
主要用于任务调度,可以按照时间间隔或Cron表达式来执行任务。
继承自TaskScheduler接口,并实现了AsyncTaskExecutor接口。
它基于线程池来执行任务,并且可以根据需要调度任务的执行。
特点:
强调任务调度和时间控制。
适用于需要按照特定时间间隔或规则执行任务的场景。
其他线程:
主要用于执行异步任务和多线程任务。
专注于线程池的管理和配置,如线程池的大小、队列容量以及线程的创建和销毁策略
特点:
强调线程池的管理和异步任务的执行。
适用于需要并发执行大量异步任务的场景。
@Configuration
public class SchedulingConfig {
@Bean
public TaskScheduler taskScheduler() {
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(4);
taskScheduler.setRemoveOnCancelPolicy(true);
taskScheduler.setThreadNamePrefix("TaskSchedulerThreadPool-");
return taskScheduler;
}
}
二、添加 ScheduledFuture 的包装类
ScheduledTaskFuture :
主要用于处理和控制定时任务的执行结果和执行状态。它提供了异步执行结果的获取、任务执行状态的控制、任务执行结果的获取和异常处理、任务的取消以及超时获取任务结果等功能,使得你可以更加方便地管理和控制定时任务的执行。
1、可以通过ScheduledTaskFuture来获取定时任务执行后的结果,查询定时任务是否已完成(isDone()方法)、是否已被取消(isCancelled()方法)或者是否正在执行(!isDone() && !isCancelled())。
2、可以调用ScheduledTaskFuture的get()方法来获取定时任务执行的结果。
3、可以调用cancel(boolean mayInterruptIfRunning)方法来取消定时任务的执行。如果参数mayInterruptIfRunning为true,尝试中断正在执行的任务;如果为false,则正在执行的任务不会被中断,但是等待执行的任务会被取消
@Component
public final class ScheduledTaskFuture {
public volatile ScheduledFuture<?> scheduledFuture;
public void cancel(){
ScheduledFuture<?> future = this.scheduledFuture;
if (future != null) {
future.cancel(true);
}
}
}
三、定时任务实体类
public class DismTimedTask {
@Id
@Column(name = "TASK_ID")
private Long taskId;
@Column(name = "TASK_NAME")
private String taskName;
@Column(name = "TASK_CRON")
private String taskCron;
@Column(name = "TASK_BEAN")
private int taskBean;
@Column(name = "TASK_METHOD_NAME")
private String taskMethodName;
@Column(name = "STATUS")
private String status;
}
四、任务的执行
public class SchedulingRunnable implements Runnable{
private String beanName;
private String methodName;
private Long taskId;
public SchedulingRunnable(String beanName, String methodName, Long taskId) {
this.beanName = beanName;
this.methodName = methodName;
this.taskId = taskId;
}
@Override
public void run() {
log.info("定时任务开始执行 - bean: {}, 方法: {}", beanName, methodName);
try {
Object target = SpringContextUtils.getBean(beanName);
if (taskId == null || taskId == 0L) {
Method method = target.getClass().getMethod(methodName);
method.invoke(target);
} else {
Method method = target.getClass().getMethod(methodName, Long.class);
method.invoke(target, taskId);
}
} catch (Exception ex) {
log.error(String.format("定时任务执行异常-bean: %s, 方法: %s", beanName, methodName));
log.error("异常:" + ex);
}
log.info("定时任务执行结束 - bean: {}, 方法: {}", beanName, methodName);
}
}
五、定时任务的创建、删除操作
@Service
@Slf4j
public class TimedTaskServiceImpl implements TimedTaskService {
private final Map<Long, ScheduledTaskFuture> scheduledTasks = new ConcurrentHashMap<>(16);
@Resource
private TaskScheduler taskScheduler;
@Transactional(rollbackFor = Exception.class)
public void updateTimedTask(TimedTask timedTask) {
SchedulingRunnable schedulingRunnable = new SchedulingRunnable(timedTask.getBean(), timedTask.getMothod(), timedTask.getTaskId());
CronTask cronTask = new CronTask(schedulingRunnable, timedTask.getTaskCron());
if ("1".equals(timedTask.getStatus())) {
if (this.scheduledTasks.containsKey(timedTask.getTaskId())){
removeCronTask(timedTask.getTaskId());
}
this.scheduledTasks.put(timedTask.getTaskId(), scheduledTask(cronTask));
} else {
removeCronTask(timedTask.getTaskId());
}
}
public void removeCronTask(Long taskId){
ScheduledTaskFuture scheduledTask = this.scheduledTasks.remove(taskId);
if (scheduledTask != null) {
scheduledTask.cancel();
}
}
public ScheduledTaskFuture scheduledTask(CronTask cronTask){
ScheduledTaskFuture scheduledTask = new ScheduledTaskFuture();
scheduledTask.scheduledFuture = this.taskScheduler.schedule(cronTask.getRunnable(), cronTask.getTrigger());
return scheduledTask;
}
}
六、获取Bean的工具类
@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);
}
}
7、程序启动时加载数据库中启用的任务
@Component
public class TimedTaskRunner implements CommandLineRunner {
@Resource
private TimedTaskService timedTaskService;
@Override
public void run(String... args) throws Exception {
timedTaskService.runAllTimedTask();
}
}
具体实现类方法
public void runAllTimedTask() {
List<DismTimedTask> timedTaskList = timedTaskDao.getDismTimedTaskByStatus("1");
if (timedTaskList != null && !timedTaskList.isEmpty()) {
for (DismTimedTask timedTask : timedTaskList) {
SchedulingRunnable schedulingRunnable = new SchedulingRunnable(null, "taskRunning", timedTask.getTaskId());
CronTask cronTask = new CronTask(schedulingRunnable, timedTask.getTaskCron());
scheduledTask(cronTask);
this.scheduledTasks.put(timedTask.getTaskId(), scheduledTask(cronTask));
log.info("定时任务已加载完毕...");
}
}
}