命令模式 + 策略模式异步的任务调度框架

422 阅读1分钟
  1. 背景

最近读了一些文章,做个总结,好多框架都是遵循这样的套路来实现任务调度的,在这里做一个比较成熟的任务调度,适用于中台的业务调用

  1. 架构图

image.png

  1. 代码

    实体部分

/**
 * 任务参数
 */
@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);
  }
}