需求:定时任务有多个类别,每个类别有多个定时任务,动态配置
原设计:按类别定时任务分类,每个定时任务写在不同的类别类下,添加定时任务cron配置
package com.cloud.project.job;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
@Component
public class TestJob {
//时间
@Scheduled(cron = "0/1 * * * * ?")
public void test() throws IOException {
System.out.println(
"current time :" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "---");
}
}
缺点:定时任务多起来会有很多cron配置,没有定时任务的统一管理,不能动态配置cron
改造:
- 定义一个接口Job,所有定时任务实现Job,
- 定义一个Enum存放所有类别,
- 定义一个Context上下文,
- 定义一个Job执行器从数据库获取所有定时任务统一管理,
定义一个Map存放所有定时任务实例对象,
通过设计模式状态模式切换定时任务类,
通过反射执行对应类对应方法
核心代码
JobContext jobContext = new JobContext();
taskMap.get(cronTask.getType()).doAction(jobContext);
Method method = jobContext.getJob().getClass().getMethod("methodName");
method.invoke(jobContext.getJob());
详细代码:
抽象类Job:
package com.cloud.project.job;
public interface Job {
public void doAction(JobContext jobContext);
}
任务枚举TaskEnum:
package com.cloud.project.enums;
import java.util.LinkedList;
import java.util.List;
public enum TaskEnum {
TEST("测试"),
private String type;
private String typeName;
TaskEnum(String typeName) {
this.typeName = typeName;
}
TaskEnum() {
}
public static List<TaskEnum> getTaskEnum() {
List<TaskEnum> list = new LinkedList<>();
for (TaskEnum value : TaskEnum.values()) {
list.add(value);
}
return list;
}
}
上下文状态类JobContext:
package com.cloud.project.job;
import com.cloud.project.pojo.SysCronTask;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
public class JobContext {
private Job job;
public JobContext() {
job = null;
}
// 测试案例
// public static Map<String, Job> taskMap=new HashMap<>();
//
// static {
// taskMap.put(TaskEnum.TEST.name(), new TestJob());
// }
//
// public static void main(String[] args)
// throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
// Context context=new Context();
// List<SysCronTask> list = new ArrayList<>();
// SysCronTask task=new SysCronTask();
// task.setType("TEST");
// list.add(task);
// for (SysCronTask cronTask : list) {
// taskMap.get(cronTask.getType()).doAction(context);
((TestJob) context.getJob()).test();
((context.getJob().getClass().getDeclaredMethod()) context.getJob()).test();
// Method method=context.getJob().getClass().getMethod("test");
// method.invoke(context.getJob());
for (Method declaredMethod : context.getJob().getClass().getDeclaredMethods()) {
System.out.println(declaredMethod.getName());
}
//
// }
// }
}
TestJob类:
package com.cloud.project.job;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
@Component
public class TestJob implement Job {
public void doAction(JobContext jobContext) {
jobContext.setJob(this);
}
//时间
public void test() throws IOException {
System.out.println(
"current time :" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "---");
}
}
任务执行器TaskCronExecutor:
package com.cloud.project.job;
import com.cloud.project.enums.TaskEnum;
import com.cloud.project.mapper.CronTaskMapper;
import com.cloud.project.pojo.SysCronTask;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;
@Component
@EnableScheduling
public class TaskCronExecutor implements SchedulingConfigurer {
@Autowired
private CronTaskMapper cronTaskMapper;
public static Map<String, Job> taskMap = new HashMap<>();
TaskCronExecutor(
TestJob testJob, HolidayJob holidayJob, WorkRestJob workRestJob, WorkJob workJob,
SceneryJob sceneryJob, LanguageJob languageJob, DealWithJob dealWithJob,
SystemJob systemJob) {
taskMap.put(TaskEnum.TEST.name(), testJob);
}
@Override
public void configureTasks(
ScheduledTaskRegistrar taskRegistrar) {
List<SysCronTask> list = cronTaskMapper.getCronTasks();
for (SysCronTask cronTask : list) {
taskRegistrar.addTriggerTask(
//1.添加任务内容(Runnable)
// () -> System.out.println("执行动态定时任务: " + LocalDateTime.now().toLocalTime()),
() -> {
JobContext jobContext = new JobContext();
taskMap.get(cronTask.getType()).doAction(jobContext);
try {
Method method = jobContext.getJob().getClass().getMethod(cronTask.getMethodName());
method.invoke(jobContext.getJob());
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
},
//2.设置执行周期(Trigger)
triggerContext -> {
//2.1 从数据库获取执行周期 todo
//2.3 返回执行周期(Date)
return new CronTrigger(cronTask.getTaskCron()).nextExecutionTime(triggerContext);
});
}
}
}
后续添加任务流程:
如果是添加类别定时任务,
- 在TaskEnum添加类别
- 在taskMap添加类别对应对象实例,
- 在对象类里实现方法,
- 数据库配置定时任务完成,
如果是添加已存在类别定时任务,
直接按照以上3和4流程执行
使用了枚举,字典,反射,状态模式
状态模式,在此贴图说明
至此完全解决了我们多类多方法代理问题
至此改造完毕!