• 【Java】用注解实现分发器


    在C/S中,客户端会向服务器发出各种请求,而服务器就要根据请求做出对应的响应。
    实际上就是客户机上执行某一个方法,将方法返回值,通过字节流的方式传输给服务器,服务器找到该请求对应的响应方法,并执行,将结果再次通过字节流的方式传输给客户机!
    下面搭建一个简单的Request和Response分发器:

    类标识的注解,只有带有该标识,才进行之后方法的扫描,否则不进行:

    1 import java.lang.annotation.ElementType;
    2 import java.lang.annotation.Retention;
    3 import java.lang.annotation.RetentionPolicy;
    4 import java.lang.annotation.Target;
    5 
    6 @Retention(RetentionPolicy.RUNTIME)
    7 @Target(ElementType.TYPE)
    8 public @interface Service {
    9 }

    方法的注解, 必须对注解中的action赋值,往后我们是要将action的值作为map中的键:

     1 import java.lang.annotation.ElementType;
     2 import java.lang.annotation.Retention;
     3 import java.lang.annotation.RetentionPolicy;
     4 import java.lang.annotation.Target;
     5 
     6 @Retention(RetentionPolicy.RUNTIME)
     7 @Target(ElementType.METHOD)
     8 public @interface Actioner {
     9     String action();
    10 }

    方法参数的注解,同样要对其name赋值,为了以后能够找到对应的参数,完成赋值:

     1 import java.lang.annotation.ElementType;
     2 import java.lang.annotation.Retention;
     3 import java.lang.annotation.RetentionPolicy;
     4 import java.lang.annotation.Target;
     5 
     6 @Retention(RetentionPolicy.RUNTIME)
     7 @Target(ElementType.PARAMETER)
     8 public @interface AParameter {
     9     String name();
    10 }

    我们需要将方法抽象成一个类,封装起来:

     1 import java.lang.reflect.Method;
     2 import java.lang.reflect.Parameter;
     3 import java.util.List;
     4 
     5 public class ActionDefination {
     6     private Class<?> klass;                     // 该方法所对应的类
     7     private Object object;                         // 执行该方法的对象
     8     private Method method;                     // 该方法
     9     private List<Parameter> paramerterList;        // 该方法的所有参数
    10     
    11     protected ActionDefination(Class<?> klass, Object object, Method method, List<Parameter> paramerterList) {
    12         this.klass = klass;
    13         this.object = object;
    14         this.method = method;
    15         this.paramerterList = paramerterList;
    16     }
    17 
    18     protected Class<?> getKlass() {
    19         return klass;
    20     }
    21 
    22     protected Object getObject() {
    23         return object;
    24     }
    25 
    26     protected Method getMethod() {
    27         return method;
    28     }
    29 
    30     protected List<Parameter> getParamerterList() {
    31         return paramerterList;
    32     }
    33     
    34 }

    所有准备工作都做好了,我们就需要通过包扫描的方式,找到带有Service 注解的类,然后找到其中带有Actioner 注解的方法,并且得到带有注解的所有参数,若其某一参数没有带注解,则应该异常处理!

    扫描包下符合要求的所有内容,最后形成一张map

      1 import java.lang.reflect.Method;
      2 import java.lang.reflect.Parameter;
      3 import java.util.ArrayList;
      4 import java.util.HashMap;
      5 import java.util.List;
      6 import java.util.Map;
      7 
      8 public class ActionFactory {
      9     private static final Map<String, ActionDefination> actionDefinationMap = new HashMap<String, ActionDefination>();
     10     
     11     // 单例模式
     12     private ActionFactory() {
     13     }
     14     public static ActionFactory newInstance() {
     15         return creatNewInstance.actionFactory;
     16     } 
     17     
     18     private static class creatNewInstance {
     19         private static final ActionFactory actionFactory = new ActionFactory(); 
     20     }
     21     
     22     // 通过类,扫描其所在包下的所有文件
     23     public void scanAction(Class<?> klass) {
     24         scanAction(klass.getPackage().getName());
     25     }
     26     
     27     //  通过包名称,扫描其下所有文件
     28     public void scanAction(String packageName) {
     29         // 包扫描,在我的上一篇博客有该方法的实现
     30         new PackageScanner() {
     31             
     32             @Override
     33             public void dealClass(Class<?> klass) {
     34                 // 只处理带有Service注解的类
     35                 if (!klass.isAnnotationPresent(Service.class)) {
     36                     return;
     37                 }
     38                 try {
     39                     // 直接由反射机制产生一个对象,将其注入
     40                     Object object = klass.newInstance();
     41                     // 扫描改类下的所有方法
     42                     scanMethod(klass, object);
     43                 } catch (Exception e) {
     44                     e.printStackTrace();
     45                 }
     46             }
     47         }.scanPackage(packageName);
     48     }
     49     
     50     // 通过对象,扫描其所有方法
     51     public void scanAction(Object object) {
     52         try {
     53             scanMethod(object.getClass(), object);
     54         } catch (Exception e) {
     55             e.printStackTrace();
     56         }
     57     }
     58 
     59     private void scanMethod(Class<?> klass, Object object) throws Exception {
     60         // 得到所有方法
     61         Method[] methods = klass.getDeclaredMethods();
     62         
     63         // 遍历所有方法,找到带有Actioner注解的方法,并得到action的值
     64         for (Method method : methods) {
     65             if (!method.isAnnotationPresent(Actioner.class)) {
     66                 continue;
     67             }
     68             Actioner actioner = method.getAnnotation(Actioner.class);
     69             String action = actioner.action();
     70             
     71             // 判断action是否已经定义
     72             if (actionDefinationMap.get(action) != null) {
     73                 throw new ActionHasDefineException("方法" + action + "已定义!");
     74             }
     75             
     76             // 得到所有参数,并判断参数是否满足要求
     77             Parameter[] parameters = method.getParameters();
     78             List<Parameter> parameterList = new ArrayList<Parameter>();
     79             for (int i = 0; i < parameters.length; i++) {
     80                 Parameter parameter = parameters[i];
     81                 if (!parameters[i].isAnnotationPresent(AParameter.class)) {
     82                     throw new MethodParameterNotDefineException("第" + (i+1) + "个参数未定义!");
     83                 }
     84                 
     85                 parameterList.add(parameter);
     86             }
     87             // 将得到的结果添加到map中
     88             addActionDefination(action, klass, object, method, parameterList);
     89         }
     90     }
     91     
     92         private void addActionDefination(String action, Class<?> klass, Object object, Method method, List<Parameter> parameterList) {
     93         ActionDefination actionDefination = new ActionDefination(klass, object, method, parameterList);
     94         actionDefinationMap.put(action, actionDefination);
     95     }
     96         
     97     protected ActionDefination getActionDefination(String action) {
     98         return actionDefinationMap.get(action);
     99     }
    100     
    101 }

    上述的ActionFactory可以帮助我们扫描到包下所有符合要求的方法,接下来就是通过传递参数执行这些方法。
    要注意,这套工具的出发点是搭载在网络上,所以传递的参数就只能是字符串或者字节流的形式,所以,我们应该对传递的参数进行处理,将其生成能供我们识别的形式。
    这里我们将参数转换为字符串的形式,我会用到gson,方便我们将对象转换为gson字符串:

     1 import java.util.HashMap;
     2 import java.util.Map;
     3 
     4 import com.google.gson.Gson;
     5 import com.google.gson.GsonBuilder;
     6 
     7 public class ArgumentMaker {
     8     // 注解AParameter中name的值 +  参数对象转换成的gson字符串所形成的map
     9     private Map<String, String> argumentMap;
    10     private Gson gson;
    11     
    12     public ArgumentMaker() {
    13         gson = new GsonBuilder().create();
    14         argumentMap = new HashMap<String, String>();
    15     }
    16     
    17     // 其name就是注解AParameter中name的值,value就是参数的具体值
    18     public ArgumentMaker add(String name, Object value) {
    19         // 通过gson将参数对象转换为gson字符串
    20         argumentMap.put(name, gson.toJson(value));
    21         return this;
    22     }
    23     
    24     // 将得到的name + 参数对象转换成的gson字符串map再次转换成gson字符串,以便于进行传输
    25     public String toOgnl() {
    26         if (argumentMap.isEmpty()) {
    27             return null;
    28         }
    29         
    30         return gson.toJson(argumentMap);
    31     }
    32     
    33 }

    接下来就是处理具体的action

     1 import java.lang.reflect.Method;
     2 import java.lang.reflect.Parameter;
     3 import java.lang.reflect.Type;
     4 import java.util.List;
     5 import java.util.Map;
     6 
     7 import com.google.gson.Gson;
     8 import com.google.gson.GsonBuilder;
     9 import com.google.gson.reflect.TypeToken;
    10 
    11 public class Addition {
    12     private static final Gson gson;
    13     private static final Type type;
    14     
    15     static {
    16         gson = new GsonBuilder().create();
    17         // 可以得到带有泛型的map类型 
    18         type = new TypeToken<Map<String, String>>(){}.getType();
    19     }
    20     
    21     public String doRequest(String action, String parameter) throws Exception {
    22         ActionDefination ad = ActionFactory.newInstance().getActionDefination(action);
    23         
    24         if (ad == null) {
    25             throw new ActionNotDefineException("方法" + action + "未定义!");
    26         }
    27         
    28         Object object = ad.getObject();
    29         Method method = ad.getMethod();
    30         
    31         Object[] parameters = getParameterArr(parameter, ad.getParamerterList());
    32         Object result = method.invoke(object, parameters);
    33         
    34         return gson.toJson(result);
    35     }
    36     
    37     private Object[] getParameterArr(String parameterString, List<Parameter> parameterList) {
    38         Object[] results = new Object[parameterList.size()];
    39         // 将字符串形式的参数,转换成map
    40         Map<String, String> parameterStringMap = gson.fromJson(parameterString, type);
    41         
    42         int index = 0;
    43         for (Parameter parameter : parameterList) {
    44             // 得到参数的注解AParameter中name的值
    45             String key = parameter.getAnnotation(AParameter.class).name();
    46             
    47             // 以name的值为键,找到参数map中value,再通过gson将其从字符串转换成具体的对象
    48             Object value = gson.fromJson(parameterStringMap.get(key),
    49                     // 得到参数的具体类型 
    50                     parameter.getParameterizedType());
    51             
    52             results[index++] = value;
    53         }
    54         
    55         return results;
    56     }

    演示如何使用

     1 @Service
     2 public class Demo {
     3 
     4     @Actioner(action="one")
     5     public void fun() {
     6         System.out.println("执行无参的fun方法");
     7     }
     8     
     9     @Actioner(action="two")
    10     public void fun(@AParameter(name="1")int parameter) {
    11         System.out.println("执行单参的fun方法: parameter = " + parameter);
    12     }
    13     
    14     @Actioner(action="three")
    15     public void fun(@AParameter(name="1")int one, 
    16             @AParameter(name="2")String two, 
    17             @AParameter(name="3")boolean three) {
    18         System.out.println("执行三参的fun方法: one = " + one + " two = " + two + " three = " + three);
    19     }
    20     
    21     private static class Student {
    22         private String name;
    23         private int age;
    24         private boolean sex;
    25         
    26         private Student(String name, int age, boolean sex) {
    27             this.name = name;
    28             this.age = age;
    29             this.sex =sex;
    30         }
    31         
    32         @Override
    33         public String toString() {
    34             return "name = " + name + ", age = " + age + ", sex = " + (sex ? "男" : "女");
    35         }
    36     }
    37     
    38     @Actioner(action="four")
    39     public void fun(@AParameter(name="1")Student student) {
    40         System.out.println("执行复杂类型参数的fun方法 :" + student);
    41     }
    42     
    43     public static void main(String[] args) throws Exception {
    44         // 扫描包,这里直接扫描Demo所在的包
    45         ActionFactory.newInstance().scanAction(Demo.class);
    46         
    47         Addition addition = new Addition();
    48         
    49         addition.doRequest("one", null);
    50         
    51         addition.doRequest("two", new ArgumentMaker()
    52                 .add("1", 3)
    53                 .toOgnl());
    54         
    55         addition.doRequest("three",new ArgumentMaker()
    56                 .add("3", true)
    57                 .add("1", 3)
    58                 .add("2", "这是第二个参数")
    59                 .toOgnl());
    60     
    61         Student student = new Student("小明", 15, true);
    62         addition.doRequest("four", new ArgumentMaker()
    63                 .add("1", student)
    64                 .toOgnl());
    65     }
    66 
    67 }

    运行结果

  • 相关阅读:
    组内分享总结
    Java虚拟机内存
    代理 正向代理 反向代理
    Class文件打包成jar并执行
    Oracle 并集交集差集
    Sysstat安装以及简单操作
    树结构列表结构相互转换 js
    nginx配置root和alias的区别
    js call apply 用法
    VS Code配置同步
  • 原文地址:https://www.cnblogs.com/a526583280/p/9745516.html
Copyright © 2020-2023  润新知