【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 }

運行結果


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM