使用Spring自定義注解實現(xiàn)任務(wù)路由
在Spring mvc的開發(fā)中,我們可以通過RequestMapping來配,當前方法用于處理哪一個URL的請求.同樣我們現(xiàn)在有一個需求,有一個任務(wù)調(diào)度器,可以按照不同的任務(wù)類型路由到不同的任務(wù)執(zhí)行器。其本質(zhì)就是通過外部參數(shù)進行一次路由和Spring mvc做的事情類似。簡單看了Spring mvc的實現(xiàn)原理之后,決定使用自定義注解的方式來實現(xiàn)以上功能。
自定義TaskHandler注解
- @Target({ElementType.TYPE})
 - @Retention(RetentionPolicy.RUNTIME)
 - @Documented
 - @Component
 - public @interface TaskHandler {
 - String taskType() default "";
 - }
 
以上定義了任務(wù)處理器的注解,其中@Component表示在spring 啟動過程中,會掃描到并且注入到容器中。taskType表示類型。
任務(wù)處理器定義
- public abstract class AbstractTaskHandler {
 - /**
 - * 任務(wù)執(zhí)行器
 - *
 - * @param task 任務(wù)
 - * @return 執(zhí)行結(jié)果
 - */
 - public abstract BaseResult execute(Task task);
 - }
 
以上定義了一個任務(wù)執(zhí)行的處理器,其他所有的具體的任務(wù)執(zhí)行器繼承實現(xiàn)這個方法。其中Task表示任務(wù)的定義,包括任務(wù)Id,執(zhí)行任務(wù)需要的參數(shù)等。
任務(wù)處理器實現(xiàn)
接下來,我們可以實現(xiàn)一個具體的任務(wù)處理器。
- @TaskHandler(taskType = "UserNameChanged")
 - public class UserNameChangedSender extends AbstractTaskHandler {
 - @Override
 - public BaseResult execute(Task task) {
 - return new BaseResult();
 - }
 - }
 
以上我們就實現(xiàn)一個用戶名修改通知的任務(wù)處理器,具體的業(yè)務(wù)邏輯這里沒有實現(xiàn)。
其中:@TaskHandler(taskType = "UserNameChanged"),這里我們指定這個Handler用于處理用戶名變更的任務(wù)
任務(wù)處理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);
 - @Override
 - 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容器中,即注冊完成
 
任務(wù)執(zhí)行
接下來我們來看下任務(wù)執(zhí)行
- public class TaskExecutor implements Job {
 - private static final String TASK_TYPE = "taskType";
 - @Override
 - 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);
 - }
 - }
 
這里發(fā)起任務(wù)執(zhí)行的是一個Job,具體過程如下
- 校驗該任務(wù)類型,有沒有在注冊中心注冊相關(guān)Handler
 - 從任務(wù)注冊中心獲取到對應(yīng)的處理的Handelr
 - 執(zhí)行該Handelr
 
以上過程就完成了,可以實現(xiàn)基于注解的一個任務(wù)路由過程。其實現(xiàn)思路來自于Spring mvc的RequestMapping的設(shè)計思路.
















 
 
 













 
 
 
 