- 背景:
最近读了一些文章,做个总结,好多框架都是遵循这样的套路来实现任务调度的,在这里做一个比较成熟的任务调度,适用于中台的业务调用
- 架构图
-
代码
实体部分
/**
* 任务参数
*/
@Data
public class ParamTask {
String id;
String name;
}
/**
* 上下文参数, 这两个可以合在一起,而且param不一定是map,最近读xxl-job的源码,看他们也是分开的
*/
@Data
public class TaskContext {
public Map<String, Object> param = new HashMap<>();
}
/**
* 自定义任务注解
*/
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Component
public @interface ScheduleCode {
String code();
}
工厂模式管理器
/**
* 定时任务工厂管理器
*/
public class ScheduleTaskManager {
/**
* 定时任务缓存
*/
private static Map<String, ScheduleTaskHandler> taskHandlers = new HashMap<>();
/**
* 注册任务处理器
*/
public static void register(ScheduleTaskHandler taskHandler) {
ScheduleCode annotation = taskHandler.getClass().getAnnotation(ScheduleCode.class);
String code = annotation.code();
taskHandlers.put(code, taskHandler);
}
/**
* 获取任务
*/
public static ScheduleTaskHandler getTaskHandler(String taskCode) {
return taskHandlers.get(taskCode);
}
}
/**
* 抽象的任务封装,只负责定义,在抽象类中来注册
*/
public interface ScheduleTaskHandler {
/**
* 实例任务前置执行
*/
default boolean preHandle(ParamTask task, TaskContext context){
return true;
};
/**
* 实例任务执行
*/
boolean handle(ParamTask instanceTask, TaskContext context);
/**
* 实例任务后置执行
*/
void postHandle(ParamTask task, TaskContext context);
}
/**
* 任务抽象类,负责子类的注册
*/
public abstract class TaskHandler implements ScheduleTaskHandler, InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
ScheduleTaskManager.register(this);
}
}
具体的任务,就是一个个的策略
@ScheduleCode(code = "Task1")
public class Task1 extends TaskHandler {
@Override
public boolean handle(ParamTask instanceTask, TaskContext context) {
Map<String, Object> param = context.getParam();
System.out.println("调度任务1");
postHandle(instanceTask,context);
return true;
}
@Override
public void postHandle(ParamTask task, TaskContext context) {
}
}
@ScheduleCode(code = "Task2")
public class Task2 extends TaskHandler {
@Override
public boolean handle(ParamTask instanceTask, TaskContext context) {
Map<String, Object> param = context.getParam();
System.out.println("调度任务2");
preHandle(instanceTask,context);
return true;
}
@Override
public void postHandle(ParamTask task, TaskContext context) {
}
}
最终暴露的命令模式
@Component
public class ScheduleCommander {
public void runTask(String taskCode, ParamTask paramTask, TaskContext context) {
ScheduleTaskHandler task = ScheduleTaskManager.getTaskHandler(taskCode);
Runnable runnable = () -> {
task.handle(paramTask, context);
};
// 调用线程池执行
ThreadPoolManager.doRun(runnable);
}
}
/**
* 线程池定义
*/
@Slf4j
public class ThreadPoolManager {
public static ExecutorService taskExecutor = new ThreadPoolExecutor(5, 100, 1L,
TimeUnit.MINUTES, new ArrayBlockingQueue<>(128),
runnable -> {
Thread thread= new Thread(runnable);
//设置线程命名规则
thread.setName("my thread - "+runnable.hashCode());
return thread;
}
, (r, executor) -> log.error("please call developer to handle error") );
public static void doRun(Runnable runnable, Object... param) {
taskExecutor.execute(() -> {
try {
runnable.run();
} catch (Exception e) {
log.error("param={} error", JSON.toJSONString(param), e);
}
});
}
}
测试代码
@SpringBootTest(classes = APP.class)
public class ScheduleTask {
@Autowired
Task1 taskSchedule1;
@Autowired
private ScheduleCommander scheduleCommander;
@Test
public void testAnno(){
// 设置任务实例属性
ParamTask task1 = new ParamTask();
task1.setName("任务1");
task1.setId(UUID.randomUUID().toString());
// 设置上下文参数
TaskContext context = new TaskContext();
HashMap<String, Object> param = new HashMap<>();
context.setParam(param);
// 调用线程池执行
scheduleCommander.runTask("Task1",task1,context);
// 任务2执行,设置参数
ParamTask task2 = new ParamTask();
task2.setName("任务2");
task2.setId(UUID.randomUUID().toString());
scheduleCommander.runTask("Task2",task2,context);
}
}