在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 }
運行結果