在上一篇文章(量化交易系统任务框架的演化之路(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字段解决了最简单的状态,可是有很多时候,状态可能更加复杂,尤其是在通过页面管理时,可能还要什么时候执行过、现在是什么状态等等。
现在还有一个任务依赖的问题还没有解决,那么如果基于上面的设计,应该如何去解决呢?