当前位置: 首页 > 科技观察

使用Spring自定义注解实现任务路由

时间:2023-03-13 15:01:58 科技观察

在Springmvc开发中,我们可以使用RequestMapping来配置当前方法使用哪个URL来处理。同样,我们现在有一个需求,一个任务调度器,可以根据不同的任务类型,路由到不同的任务执行器。其实质就是通过外部参数进行路由,类似于Springmvc做的事情。简单看了下Springmvc的实现原理后,决定使用自定义注解来实现上述功能。自定义TaskHandler注解@Target({ElementType.TYPE})@Retention(RetentionPolicy.RUNTIME)@Documented@Componentpublic@interfaceTaskHandler{StringtaskType()default";}上面定义了任务处理器的注解,其中@Component表示在spring期间启动时,它被扫描并注入到容器中。taskType表示类型。任务处理器定义publicabstractclassAbstractTaskHandler{/***任务执行器**@paramtask任务*@return执行结果*/publicabstractBaseResultexecute(Tasktask);}上面定义了一个任务执行处理器,其他所有具体的任务执行器都继承实现这个方法。其中,Task表示任务的定义,包括任务Id、执行任务所需的参数等。任务处理器实现接下来,我们可以实现一个具体的任务处理器。@TaskHandler(taskType="UserNameChanged")publicclassUserNameChangedSenderextendsAbstractTaskHandler{@OverridepublicBaseResultexecute(Tasktask){returnnewBaseResult();}}上面我们实现了一个用户名修改通知的taskhandler,具体的业务逻辑这里就不实现了。其中:@TaskHandler(taskType="UserNameChanged"),这里我们指定这个Handler来处理更改用户名的任务(TaskHandlerRegister.class);@OverrideprotectedvoidinitApplicationContext(ApplicationContextcontext)throwsBeansException{super.initApplicationContext(context);MaptaskBeanMap=context.getBeansWithAnnotation(TaskHandler.class);taskBeanMap.keySet().forEach(beanName->{Objectbean=taskBeanMap.get(beanName);Classclazz=bean.getClass();if(beaninstanceofAbstractTaskHandler&&clazz.getAnnotation(TaskHandler.class)!=null){TaskHandlertaskHandler=(TaskHandler)clazz.getAnnotation(TaskHandler.class);StringtaskType=taskHandler.taskType();if(TASK_HANDLERS_MAP.keySet().contains(taskType)){thrownewRuntimeException("TaskTypehasExits.TaskType="+taskType);}TASK_HANDLERS_MAP.put(taskHandler.taskType(),(AbstractTaskHandler)taskBeanMap.get(beanName));LOGGER.info("TaskHandlerRegister.taskType={},beanName={}",taskHandler.taskType(),beanName);}});}publicstaticAbstractTaskHandlergetTaskHandler(StringtaskType){returnTASK_HANDLERS_MAP.get(taskType);}}这里继承了Spring的ApplicationObjectSupport类,具体的注册过程如下注解TaskHandler的bean检查bean是否是的AbstractTaskHandler类型,获取taskType,将bean放入TASK_HANDLERS_MAP容器,完成任务执行接下来我们看任务执行;if(TaskHandlerRegister.getTaskHandler(taskType)==null){thrownewRuntimeException("找不到taskHandler,taskType="+taskType);}AbstractTaskHandlerabstractHandler=TaskHandlerRegister.getTaskHandler(taskType);returnabstractHandexecute(task);}}这里发起任务该任务作为作业执行。具体流程如下,验证任务的类型,相关的Handler是否在注册表中注册。相应处理的Handelr是从任务注册表中获取的。执行Handelr后,以上流程就完成了,一个基于注解的任务路由流程的实现思路来源于SpringMVC中RequestMapping的设计思路。