CREATE TABLE `t_task` (
`id` int(30) NOT NULL AUTO_INCREMENT,
`table_name` varchar(30) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL,
`job_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`class_name` varchar(60) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`method` varchar(40) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
`cron` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '-' COMMENT '设置为 - , 则表示关闭自动执行。',
`status` int(2) NULL DEFAULT 0,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;
package cn.lacknb.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
/**
* @author gitsilence
* @version 1.0
* @date 2020/10/4 0004 下午 17:03
* @mail gitsilence@lacknb.cn
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Task implements Serializable {
private Integer id;
private String tableName;
private String cron;
private String jobName;
private String className;
private String method;
private Integer status;
}
这种,我们每次更改cron表达式之后,需要重启服务器 才能生效。
package cn.lacknb.schedule.config;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* @author gitsilence
* @version 1.0
* @date 2020/10/4 0004 下午 18:04
* @mail gitsilence@lacknb.cn
*/
@Component
public class ApplicationContextHelper implements ApplicationContextAware {
private static ApplicationContext applicationContext;
public ApplicationContextHelper() {
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
ApplicationContextHelper.applicationContext = applicationContext;
}
public static Object getBean(String beanName) {
return applicationContext != null?applicationContext.getBean(beanName):null;
}
}
package cn.lacknb.schedule.config;
import cn.lacknb.pojo.Task;
import cn.lacknb.service.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.List;
/**
* @author gitsilence
* @version 1.0 这种方式不支持 实时更改 cron 表达式。
* @date 2020/10/4 0004 下午 17:55
* @mail gitsilence@lacknb.cn
*/
@Component
public class ScheduleSetting implements SchedulingConfigurer {
@Autowired
private TaskService taskService;
@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
// 获取 所有的任务
List<Task> tasks = taskService.selectTask();
System.out.println("total tasks count: " + tasks.size());
for (Task task : tasks) {
scheduledTaskRegistrar.addTriggerTask(getRunnable(task), getTrigger(task));
}
}
/**
* 转换首字母小写
*
* @param str
* @return
*/
public static String lowerFirstCapse(String str) {
char[] chars = str.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
private Runnable getRunnable (Task task) {
System.out.println("runnable setting success");
return new Runnable() {
@Override
public void run() {
Class<?> clazz;
try {
clazz = Class.forName(task.getClassName());
String className = lowerFirstCapse(clazz.getSimpleName());
System.out.println("simpleName: " + clazz.getSimpleName());
Object bean = ApplicationContextHelper.getBean(className);
Method method = ReflectionUtils.findMethod(bean.getClass(), task.getMethod());
ReflectionUtils.invokeMethod(method, bean);
} catch (ClassNotFoundException e){
e.printStackTrace();
}
}
};
}
private Trigger getTrigger (Task task) {
System.out.println("getTrigger setting success");
return new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
CronTrigger trigger = new CronTrigger(task.getCron());
Date nextExec = trigger.nextExecutionTime(triggerContext);
return nextExec;
}
};
}
}
这种方式,支持 实时更改。 当我们进行增加、修改任务的时候,需要 把之前的调度任务取消掉,然后再重新开始。
package cn.lacknb.schedule.Itf;
/**
* @author gitsilence
* @version 1.0
* @date 2020/10/4 0004 下午 19:20
* @mail gitsilence@lacknb.cn
*/
public interface ScheduleInterface {
void start ();
void stop ();
}
这里需要 第一种的 ApplicationContextHelper
package cn.lacknb.schedule.Itf;
import cn.lacknb.pojo.Task;
import cn.lacknb.schedule.config.ApplicationContextHelper;
import cn.lacknb.service.TaskService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import org.springframework.scheduling.TriggerContext;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Service;
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.*;
import java.util.concurrent.ScheduledFuture;
/**
* @author gitsilence
* @version 1.0
* @date 2020/10/4 0004 下午 19:21
* @mail gitsilence@lacknb.cn
*/
@Service
public class ScheduleItfImpl implements ScheduleInterface {
@Autowired
private TaskScheduler taskScheduler;
private static Set<ScheduledFuture> set;
static {
System.out.println("static code is running ~ ~");
// 线程安全的 列表
set = Collections.synchronizedSet(new HashSet<>());
}
// private ScheduledFuture scheduledFuture;
@Autowired
private TaskService taskService;
/**
* 转换首字母小写
*
* @param str
* @return
*/
public static String lowerFirstCapse(String str) {
char[] chars = str.toCharArray();
chars[0] += 32;
return String.valueOf(chars);
}
@Override
public void start() {
System.out.println("start method ~ ~ ~");
List<Task> tasks = taskService.selectTask();
System.out.println("total tasks: " + tasks.size());
for (Task task : tasks) {
ScheduledFuture<?> schedule = taskScheduler.schedule(new Runnable() {
@Override
public void run() {
Class<?> clazz;
try {
clazz = Class.forName(task.getClassName());
String className = lowerFirstCapse(clazz.getSimpleName());
System.out.println("simpleName: " + clazz.getSimpleName());
Object bean = ApplicationContextHelper.getBean(className);
Method method = ReflectionUtils.findMethod(bean.getClass(), task.getMethod());
ReflectionUtils.invokeMethod(method, bean);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}, new Trigger() {
@Override
public Date nextExecutionTime(TriggerContext triggerContext) {
CronTrigger trigger = new CronTrigger(task.getCron());
Date nextExec = trigger.nextExecutionTime(triggerContext);
return nextExec;
}
});
set.add(schedule);
}
}
@Override
public void stop() {
if (set.size() != 0) {
for (ScheduledFuture scheduledFuture : set) {
scheduledFuture.cancel(false);
}
}
}
}
package cn.lacknb.schedule.config;
import cn.lacknb.schedule.Itf.ScheduleInterface;
import cn.lacknb.schedule.Itf.ScheduleItfImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* @author gitsilence
* @version 1.0 继承Application接口 项目 启动时 会按照执行顺序执行run方法
*
* 通过设置order的value来指定执行的顺序
* @date 2020/10/4 0004 下午 19:33
* @mail gitsilence@lacknb.cn
*/
@Component
@Order(value = 1)
public class InitialSchedulerService implements ApplicationRunner {
@Autowired
private ScheduleInterface scheduleInterface;
/**
* 项目启动的时候,启动该方法。
* @param args
* @throws Exception
*/
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println(new Date());
scheduleInterface.start();
}
}