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

自定义TaskHandler注解

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

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

任务处理器定义

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

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

任务处理器实现

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

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

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

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

任务处理Handler注册

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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类,具体的注册过程如下

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

任务执行

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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);
  }
}

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

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

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

使用Spring自定义注解实现任务路由的方法的更多相关文章

  1. spring - 自定义注解

    本自定义注解的作用:用于控制类方法的调用,只有拥有某个角色时才能调用. java内置注解 1.@Target 表示该注解用于什么地方,可能的 ElemenetType 参数包括: ElemenetTy ...

  2. spring自定义注解实现登陆拦截器

    1.spring自定义注解实现登陆拦截器 原理:定义一个注解和一个拦截器,拦截器拦截所有方法请求,判断该方法有没有该注解.没有,放行:有,要进行验证.从而实现方法加注解就需要验证是否登陆. 2.自定义 ...

  3. Spring 自定义注解,配置简单日志注解

    java在jdk1.5中引入了注解,spring框架也正好把java注解发挥得淋漓尽致. 下面会讲解Spring中自定义注解的简单流程,其中会涉及到spring框架中的AOP(面向切面编程)相关概念. ...

  4. 照虎画猫写自己的Spring——自定义注解

    Fairy已经实现的功能 读取XML格式配置文件,解析得到Bean 读取JSON格式配置文件,解析得到Bean 基于XML配置的依赖注入 所以,理所当然,今天该实现基于注解的依赖注入了. 基于XML配 ...

  5. Spring自定义注解扫描的实现

    目标:实现自定义spring自动扫描注解.主要为后期实现分布式服务框架自动注解提供技术支持 技术分析:通过配置组件扫描标签使spring解析标签. 1. JewelScanBeanDefaultPar ...

  6. 2018-02-11 发布 spring 自定义注解(annotation)与 aop获取注解

    知识点: Java自定义注解.spring aop @aspect的使用 首先我们先介绍Java自定义注解. 在开发过程中,我们实现接口的时候,会出现@Override,有时还会提示写@Suppres ...

  7. 深入Spring:自定义注解加载和使用

    前言 在工作中经常使用Spring的相关框架,免不了去看一下Spring的实现方法,了解一下Spring内部的处理逻辑.特别是开发Web应用时,我们会频繁的定义@Controller,@Service ...

  8. 【转】spring 自定义注解(annotation)与 aop获取注解

    首先我们先介绍Java自定义注解. 在开发过程中,我们实现接口的时候,会出现@Override,有时还会提示写@SuppressWarnings.其实这个就是Java特有的特性,注解. 注解就是某种注 ...

  9. Spring 自定义注解,结合AOP,配置简单日志注解 (转)

    java在jdk1.5中引入了注解,spring框架也正好把java注解发挥得淋漓尽致. 下面会讲解Spring中自定义注解的简单流程,其中会涉及到spring框架中的AOP(面向切面编程)相关概念. ...

随机推荐

  1. 用MVC5+EF6+WebApi 做一个考试功能(六) 仓储模式 打造EF通用仓储类

    前言 年底工作比较忙,年度总结还没写,项目要上线,回老家过年各种准备.尤其是给长辈给侄子侄女准备礼物头都大了. 原来想年前先出一版能用的,我看有点悬了,尽量先把大体功能弄出来,扔掉一些,保证能考试,然 ...

  2. python IPv6 十进制和十六进制互转

    IPv6 转 十进制: #!/usr/bin/python # -*- coding: UTF-8 -*- import re def ipv62dec(ipv6): if checkipv6(ipv ...

  3. Django(wsgiref、jinja2模块使用介绍)

    day60 wsgiref比较稳定 """ 根据URL中不同的路径返回不同的内容--函数进阶版 返回HTML页面 让网页动态起来 wsgiref模块版 "&qu ...

  4. python操作mongodb实例

    安装pymongo扩展 import pymongo; client = pymongo.MongoClient(host='10.48.176.170',port=27017); db = clie ...

  5. Vue 部署单页应用,刷新页面 404/502 报错

    在 Vue 项目中,可以选择 hash或者 history.pushState() 实现路由跳转.如果在路由中使用history模式: export default new Router({ mode ...

  6. JSP知识汇总

    JSP知识汇总 一.简介 > HTML - HTML擅长显示一个静态的网页,但是不能调用Java程序. > Servlet - Servlet擅长调用Java程序和后台进行交互,但是它不擅 ...

  7. python学习笔记06-enumerate()

    enumerate()   python 内置函数  枚举 列举的意思 对于一个可迭代的(iterable)/可遍历的对象(如列表.字符串),enumerate将其组成一个索引序列,利用它可以同时获得 ...

  8. Python绑定方法与非绑定方法

    绑定方法 绑定方法(绑定给谁,谁来调用就自动将它本身当作第一个参数传入): 绑定到类的方法:用classmethod装饰器装饰的方法,类在使用时会将类本身当做参数传给类方法的第一个参数(即便是对象来调 ...

  9. Pycharm使用Git

    Pycharm使用Git 1.设置git程序路径 2.设置github连接 3.创建git respository 4.提交文件 5.共享给GitHub 6.修改文件push到版本库 7.从版本库ch ...

  10. sql server 只读帐号设置能读取存储过程,view等内容。

    如果设定了某个帐号是只读权限,是无法查看存储过程的,比如你用 sp_helptext '存储过程名' ,这样子会提示权限不足或者存储过程不存在,其实就是没权限, 要再给这个只读帐号用 sa 赋予它查看 ...