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

开发
在Spring mvc的开发中,我们可以通过RequestMapping来配,当前方法用于处理哪一个URL的请求.同样我们现在有一个需求,有一个任务调度器,可以按照不同的任务类型路由到不同的任务执行器。其本质就是通过外部参数进行一次路由和Spring mvc做的事情类似。简单看了Spring mvc的实现原理之后,决定使用自定义注解的方式来实现以上功能。

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

在Spring mvc的开发中,我们可以通过RequestMapping来配,当前方法用于处理哪一个URL的请求.同样我们现在有一个需求,有一个任务调度器,可以按照不同的任务类型路由到不同的任务执行器。其本质就是通过外部参数进行一次路由和Spring mvc做的事情类似。简单看了Spring mvc的实现原理之后,决定使用自定义注解的方式来实现以上功能。

自定义TaskHandler注解

  1. @Target({ElementType.TYPE}) 
  2. @Retention(RetentionPolicy.RUNTIME) 
  3. @Documented 
  4. @Component 
  5. public @interface TaskHandler { 
  6.  
  7.     String taskType() default ""
  8.  

以上定义了任务处理器的注解,其中@Component表示在spring 启动过程中,会扫描到并且注入到容器中。taskType表示类型。

任务处理器定义

  1. public abstract class AbstractTaskHandler { 
  2.  
  3.     /** 
  4.      * 任务执行器 
  5.      * 
  6.      * @param task 任务 
  7.      * @return 执行结果 
  8.      */ 
  9.      public abstract BaseResult execute(Task task); 
  10.  

以上定义了一个任务执行的处理器,其他所有的具体的任务执行器继承实现这个方法。其中Task表示任务的定义,包括任务Id,执行任务需要的参数等。

任务处理器实现

接下来,我们可以实现一个具体的任务处理器。

  1. @TaskHandler(taskType = "UserNameChanged"
  2. public class UserNameChangedSender extends AbstractTaskHandler { 
  3.     @Override 
  4.     public BaseResult execute(Task task) { 
  5.       return new BaseResult(); 
  6.     } 
  7.  

以上我们就实现一个用户名修改通知的任务处理器,具体的业务逻辑这里没有实现。

其中:@TaskHandler(taskType = "UserNameChanged"),这里我们指定这个Handler用于处理用户名变更的任务

任务处理Handler注册

  1. public class TaskHandlerRegister extends ApplicationObjectSupport { 
  2.  
  3.     private final static Map<String, AbstractTaskHandler> TASK_HANDLERS_MAP = new HashMap<>(); 
  4.  
  5.     private static final Logger LOGGER = LoggerFactory.getLogger(TaskHandlerRegister.class); 
  6.  
  7.     @Override 
  8.     protected void initApplicationContext(ApplicationContext context) throws BeansException { 
  9.         super.initApplicationContext(context); 
  10.         Map<String, Object> taskBeanMap = context.getBeansWithAnnotation(TaskHandler.class); 
  11.         taskBeanMap.keySet().forEach(beanName -> { 
  12.             Object bean = taskBeanMap.get(beanName); 
  13.             Class clazz = bean.getClass(); 
  14.             if (bean instanceof AbstractTaskHandler && clazz.getAnnotation(TaskHandler.class) != null) { 
  15.                 TaskHandler taskHandler = (TaskHandler) clazz.getAnnotation(TaskHandler.class); 
  16.                 String taskType = taskHandler.taskType(); 
  17.                 if (TASK_HANDLERS_MAP.keySet().contains(taskType)) { 
  18.                     throw new RuntimeException("TaskType has Exits. TaskType=" + taskType); 
  19.                 } 
  20.                 TASK_HANDLERS_MAP.put(taskHandler.taskType(), (AbstractTaskHandler) taskBeanMap.get(beanName)); 
  21.                 LOGGER.info("Task Handler Register. taskType={},beanName={}", taskHandler.taskType(), beanName); 
  22.             } 
  23.         }); 
  24.     } 
  25.  
  26.     public static AbstractTaskHandler getTaskHandler(String taskType) { 
  27.         return TASK_HANDLERS_MAP.get(taskType); 
  28.     } 
  29.  

这里继承了Spring的ApplicationObjectSupport类,具体的注册过程如下

  1. Spring完成bean的初始化
  2. 查找spring的容器中,所有带有TaskHandler注解的bean
  3. 校验bean是否为AbstractTaskHandler类型,获取到taskType
  4. 把该bean放到TASK_HANDLERS_MAP容器中,即注册完成

任务执行

接下来我们来看下任务执行

  1. public class TaskExecutor implements Job { 
  2.  
  3.     private static final String TASK_TYPE = "taskType"
  4.  
  5.     @Override 
  6.     public BaseResult execute(Task task){ 
  7.         String taskType=task.getTaskType(); 
  8.         if (TaskHandlerRegister.getTaskHandler(taskType) == null) { 
  9.             throw new RuntimeException("can't find taskHandler,taskType=" + taskType); 
  10.         } 
  11.         AbstractTaskHandler abstractHandler = TaskHandlerRegister.getTaskHandler(taskType); 
  12.         return abstractHandler.execute(task); 
  13.     } 
  14.  

这里发起任务执行的是一个Job,具体过程如下

  1. 校验该任务类型,有没有在注册中心注册相关Handler
  2. 从任务注册中心获取到对应的处理的Handelr
  3. 执行该Handelr

以上过程就完成了,可以实现基于注解的一个任务路由过程。其实现思路来自于Spring mvc的RequestMapping的设计思路. 

责任编辑:庞桂玉 来源: wangyan9110的博客
相关推荐

2023-10-24 13:48:50

自定义注解举值验证

2020-11-25 11:20:44

Spring注解Java

2021-12-30 12:30:01

Java注解编译器

2022-02-17 07:10:39

Nest自定义注解

2023-10-09 07:37:01

2015-06-10 10:54:24

自定义路PHP

2009-08-13 09:07:36

Java多线程

2020-09-04 13:30:43

Java自定义代码

2018-06-21 14:46:03

Spring Boot异步调用

2023-10-11 07:57:23

springboot微服务

2023-10-23 08:18:50

扫描SpringBean

2024-04-03 09:18:03

Redis数据结构接口防刷

2022-11-10 07:53:54

Spring参数校验

2018-07-17 14:47:55

Windows 10Windows任务栏

2022-05-18 07:44:13

自定义菜单前端

2009-09-07 22:00:15

LINQ自定义

2022-11-01 11:15:56

接口策略模式

2021-02-20 11:40:35

SpringBoot占位符开发技术

2016-08-23 13:21:15

MVC路由视图

2009-06-23 11:35:44

JSF的Naviati
点赞
收藏

51CTO技术栈公众号