在spring
mvc的開發中,我們可以通過requestmapping來配,目前方法用于處理哪一個url的請求.同樣我們現在有一個需求,有一個任務排程器,可以按照不同的任務類型路由到不同的任務執行器。其本質就是通過外部參數進行一次路由和spring
mvc做的事情類似。簡單看了spring mvc的實作原理之後,決定使用自定義注解的方式來實作以上功能。
自定義taskhandler注解
@target({elementtype.type})
@retention(retentionpolicy.runtime)
@documented
@component
public @interface taskhandler {
string tasktype() default "";
}
以上定義了任務處理器的注解,其中@component表示在spring 啟動過程中,會掃描到并且注入到容器中。tasktype表示類型。
任務處理器定義
public abstract class abstracttaskhandler {
/**
* 任務執行器
*
* @param task 任務
* @return 執行結果
*/
public abstract baseresult execute(task task);
以上定義了一個任務執行的處理器,其他所有的具體的任務執行器繼承實作這個方法。其中task表示任務的定義,包括任務id,執行任務需要的參數等。
任務處理器實作
接下來,我們可以實作一個具體的任務處理器。
@taskhandler(tasktype = "usernamechanged")
public class usernamechangedsender extends abstracttaskhandler {
@override
public baseresult execute(task task) {
return new baseresult();
}
以上我們就實作一個使用者名修改通知的任務處理器,具體的業務邏輯這裡沒有實作。
其中:@taskhandler(tasktype = "usernamechanged"),這裡我們指定這個handler用于處理使用者名變更的任務
任務處理handler注冊
public class taskhandlerregister extends applicationobjectsupport {
private final static map<string, abstracttaskhandler> task_handlers_map = new hashmap<>();
private static final logger logger = loggerfactory.getlogger(taskhandlerregister.class);
protected void initapplicationcontext(applicationcontext context) throws beansexception {
super.initapplicationcontext(context);
map<string, object> taskbeanmap = context.getbeanswithannotation(taskhandler.class);
taskbeanmap.keyset().foreach(beanname -> {
object bean = taskbeanmap.get(beanname);
class clazz = bean.getclass();
if (bean instanceof abstracttaskhandler && clazz.getannotation(taskhandler.class) != null) {
taskhandler taskhandler = (taskhandler) clazz.getannotation(taskhandler.class);
string tasktype = taskhandler.tasktype();
if (task_handlers_map.keyset().contains(tasktype)) {
throw new runtimeexception("tasktype has exits. tasktype=" + tasktype);
}
task_handlers_map.put(taskhandler.tasktype(), (abstracttaskhandler) taskbeanmap.get(beanname));
logger.info("task handler register. tasktype={},beanname={}", taskhandler.tasktype(), beanname);
}
});
public static abstracttaskhandler gettaskhandler(string tasktype) {
return task_handlers_map.get(tasktype);
這裡繼承了spring的applicationobjectsupport類,具體的注冊過程如下
spring完成bean的初始化
查找spring的容器中,所有帶有taskhandler注解的bean
校驗bean是否為abstracttaskhandler類型,擷取到tasktype
把該bean放到task_handlers_map容器中,即注冊完成
任務執行
接下來我們來看下任務執行
public class taskexecutor implements job {
private static final string task_type = "tasktype";
public baseresult execute(task task){
string tasktype=task.gettasktype();
if (taskhandlerregister.gettaskhandler(tasktype) == null) {
throw new runtimeexception("can't find taskhandler,tasktype=" + tasktype);
}
abstracttaskhandler abstracthandler = taskhandlerregister.gettaskhandler(tasktype);
return abstracthandler.execute(task);
這裡發起任務執行的是一個job,具體過程如下
校驗該任務類型,有沒有在注冊中心注冊相關handler
從任務注冊中心擷取到對應的處理的handelr
執行該handelr
以上過程就完成了,可以實作基于注解的一個任務路由過程。其實作思路來自于spring mvc的requestmapping的設計思路.
作者:wangyan9110
來源:51cto