1、数据库
实现类这里省略
2、ScheduledConfig 配置线程池
package com.kadmus.electric.config;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
@Configuration
@Slf4j
public class ScheduledConfig {
@Bean
public ThreadPoolTaskScheduler threadPoolTaskScheduler(){
log.info("创建定时任务调度线程池");
ThreadPoolTaskScheduler threadPoolTaskScheduler = new ThreadPoolTaskScheduler();
threadPoolTaskScheduler.setPoolSize(20);
threadPoolTaskScheduler.setThreadNamePrefix("taskExecutor-");
threadPoolTaskScheduler.setWaitForTasksToCompleteOnShutdown(true);
threadPoolTaskScheduler.setAwaitTerminationSeconds(60);
return threadPoolTaskScheduler;
}
}
3、项目启动时初始化定时任务
package com.kadmus.electric.component;
import com.kadmus.electric.service.ScheduledTaskService;
import com.kadmus.service.IScheduledJobService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.stereotype.Component;
@Component
@Slf4j
public class ScheduledTaskRunner implements ApplicationRunner {
@Autowired
private ScheduledTaskService scheduledTaskService;
@Override
public void run(ApplicationArguments applicationArguments) throws Exception {
log.info("----初始化定时任务开始----");
scheduledTaskService.initTask();
log.info("----初始化定时任务完成----");
}
}
4、ScheduledTaskService接口
package com.kadmus.electric.service;
import com.kadmus.entity.ScheduledJob;
public interface ScheduledTaskService {
Boolean start(ScheduledJob scheduledJob);
Boolean stop(String jobKey);
Boolean restart(ScheduledJob scheduledJob);
void initTask();
}
5、ScheduledTaskServiceImpl 实现类
package com.kadmus.electric.service.impl;
import com.kadmus.electric.service.ScheduledOfTask;
import com.kadmus.electric.service.ScheduledTaskService;
import com.kadmus.electric.util.SpringContextUtil;
import com.kadmus.entity.ScheduledJob;
import com.kadmus.entity.ScheduledJobCriteria;
import com.kadmus.service.IScheduledJobService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.locks.ReentrantLock;
@Service
@Slf4j
public class ScheduledTaskServiceImpl implements ScheduledTaskService {
/**
* 可重载入锁
*/
private ReentrantLock lock=new ReentrantLock();
/**
* 定时任务线程池
*/
@Autowired
private ThreadPoolTaskScheduler threadPoolTaskScheduler;
/**
* 启动状态的定时任务集合
*/
public Map<String, ScheduledFuture> scheduledFutureMap = new ConcurrentHashMap<>();
@Autowired
private IScheduledJobService scheduledJobService;
@Override
public Boolean start(ScheduledJob scheduledJob) {
String jobKey = scheduledJob.getBeanName();
log.info("启动定时任务"+jobKey);
//添加锁放一个线程启动,防止多人启动多次
lock.lock();
log.info("加锁完成");
try {
if(this.isStart(jobKey)){
log.info("当前任务在启动状态中");
return false;
}
//任务启动
this.doStartTask(scheduledJob);
} finally {
lock.unlock();
log.info("解锁完毕");
}
return true;
}
/**
* 任务是否已经启动
*/
private Boolean isStart(String taskKey) {
//校验是否已经启动
if (scheduledFutureMap.containsKey(taskKey)) {
if (!scheduledFutureMap.get(taskKey).isCancelled()) {
return true;
}
}
return false;
}
/**
* 执行启动任务
*/
public void doStartTask(ScheduledJob sj){
log.info("任务加载中{}",sj.getBeanName());
if(sj.getStatus().intValue() != 1)
return;
Class<?> clazz;
ScheduledOfTask task;
try {
task = new ScheduledOfTask(sj.getBeanName(),
sj.getMethodName(), sj.getParams());
} catch (NoSuchMethodException e) {
throw new RuntimeException(sj.getBeanName(), e);
}
Assert.isAssignable(ScheduledOfTask.class, task.getClass(), "定时任务类必须实现ScheduledOfTask接口");
ScheduledFuture scheduledFuture = threadPoolTaskScheduler.schedule(task,(triggerContext -> new CronTrigger(sj.getCronExpression()).nextExecutionTime(triggerContext)));
scheduledFutureMap.put(sj.getBeanName(),scheduledFuture);
}
@Override
public Boolean stop(String jobKey) {
log.info("停止任务 "+jobKey);
boolean flag = scheduledFutureMap.containsKey(jobKey);
log.info("当前实例是否存在 "+flag);
if(flag){
ScheduledFuture scheduledFuture = scheduledFutureMap.get(jobKey);
scheduledFuture.cancel(true);
scheduledFutureMap.remove(jobKey);
}
return flag;
}
@Override
public Boolean restart(ScheduledJob scheduledJob) {
log.info("重启定时任务"+scheduledJob.getBeanName());
//停止
this.stop(scheduledJob.getBeanName());
return this.start(scheduledJob);
}
@Override
public void initTask() {
log.info("查询任务");
ScheduledJobCriteria cir=new ScheduledJobCriteria();
List<ScheduledJob> list = scheduledJobService.search(cir);
for (ScheduledJob sj : list) {
if(sj.getStatus().intValue() == -1) //未启用
continue;
doStartTask(sj);
}
}
}
6、ScheduledOfTask
package com.kadmus.electric.service;
import com.kadmus.electric.util.SpringContextUtil;
import org.apache.commons.lang.StringUtils;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
public class ScheduledOfTask implements Runnable{
private Object target;
private Method method;
private String params;
public ScheduledOfTask(String beanName, String methodName, String params) throws NoSuchMethodException {
this.target = SpringContextUtil.getBean(beanName);
this.params = params;
if(StringUtils.isNotBlank(params)){
this.method = target.getClass().getDeclaredMethod(methodName, String.class);
}else{
this.method = target.getClass().getDeclaredMethod(methodName);
}
}
@Override
public void run() {
try {
ReflectionUtils.makeAccessible(method);
if(StringUtils.isNotBlank(params)){
method.invoke(target, params);
}else{
method.invoke(target);
}
}catch (Exception e) {
throw new RuntimeException("执行定时任务失败", e);
}
}
}
7、测试类
package com.kadmus.electric.task;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component("schenduTest")
@Slf4j
public class SchenduTest {
public void execute(){
log.info("定时任务执行时间{}",System.currentTimeMillis());
}
}