在上一篇文章( 量化交易系统任务框架的演化之路(1)定时任务 )的结尾提了三个问题,今天就来第一版的解决方案。
之前的实现方案中,所有任务都是无状态、无管理的,人工干预就比较麻烦。其实解决这个问题的方法很简单,那就是增加一个“状态”,看一下这个流程图:
通过这个流程图就可以很明显的看出,重入的问题一下子就解决了。道理明白了,那么实现起来就很简单了。直接把框架代码放这里,供参考。
通过注解来表示是否为要管理的任务,在这里指定了一个属性name,管理容器可以很方便通过这个名字找到对应任务实例,完成一系列的操作。
@Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Component public @interface QuantManagedTask { String name(); }
下面这个类是所有任务的基类,里面包含了任务的框架方法,start方法用来启动任务,启动时会检查当前任务的状态,如果没有在执行则启动,否则直接跳过;stop方法用来停止任务。
public abstract class QuantTask { //任务状态 private boolean isRunning = false; /** * 启动当前任务,改变状态,执行任务 */ public void start(){ //任务已经在执行中,则直接返回 if(isRunning): return; isRunning = true; doTask(); //执行完毕后停止 stop(); } // 实际的任务内容 public abstract void doTask(); /** * 停止当前任务,改变状态 */ public void stop(){ isRunning = false; } /** * 获取任务是否在执行中 */ public boolean isRunning(){ return isRunning; } }
下面就是任务的管理容器,容器负责任务的启动和结束。在系统启动时,会将所有通过注解标注和继承了QuantTask的任务类预先加载进来,建立任务名称和任务实例对应的Map,那么就可以很容易的通过名字找到相应的任务实例。
@Component public class QuantTaskManager implements BeanPostProcessor{ protected Map<String, QuantTask> nameTaskMap = new HashMap<>(); @Override public Object postProcessBeforeInitialization(Object bean, String s) throws BeansException { return bean; } @Override public Object postProcessAfterInitialization(Object bean, String s) throws BeansException { if(bean instanceof QuantTask) { try { QuantTask task = (QuantTask) bean; QuantManagedTask quantManagedTask = AopUtils.getTargetClass(bean).getAnnotation(QuantManagedTask.class); nameTaskMap.put(quantManagedTask.name(), task); }catch (Exception e){ e.printStackTrace(); } } return bean; } public void execute(String taskName) { nameTaskMap.get(taskName).start(); } }
下面这个就是一个示例任务类,可以直接通过其名字sample_task启动它。
@QuantManagedTask(name="sample_task") public void SampleQuantTask extends QuantTask(){ public void doTask(){ //Do something } }
增加了管理容器,我们就可以很容易的实现在页面上对任务进行管理的功能。当然了,这里只是通过一个isRunning字段解决了最简单的状态,可是有很多时候,状态可能更加复杂,尤其是在通过页面管理时,可能还要什么时候执行过、现在是什么状态等等。
现在还有一个任务依赖的问题还没有解决,那么如果基于上面的设计,应该如何去解决呢?