JAVA早期,Web框架都使用XML文件来管理接口,比如Struts,spring。其组件基本都是定义在XML文件中,然后系统启动时通过XML文件来加载。这种模式开发出的系统,文件臃肿不堪,非常难以维护和管理。后来Java带来了Annotation,再加上Java的反射机制。为我们提供了非常便利的方式来管理接口,搭建出的系统就非常的简洁和优雅。来看看其具体应用。 首先我们定义一个作用于方法上的Annotation package webfunc; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface RequestFunction { String action(); boolean cached() default false; boolean isSynchronize() default false; String explain() default "Request function"; } // @RequestFunction (action = "personVerify") // public ResponseData personVerifyMethod(WebSystemContext context) { //.............. // } 这个Annotation里的ElementType.METHOD属性代表本注解是作用在方法上的。还可以根据系统需要给他定义其他功能,比如缓存,异步操作等等。注解定义好,就可以像上面的业务代码这样去使用,来看看系统是如何加载这个注解的。 在继续之前,简要说明一下,注解的内容是这样的:@RequestFunction (action = “personVerify”)。 需要执行的代码是这样的:public ResponseData personVerifyMethod(WebSystemContext context)。 这就需要有一个对应关系,分别代表请求指令和方法,通过请求指令来执行对应的方法。 先定义一个实际的执行方法的调用类。里面有需要被调用的class和method,只需要调用method就可以。 package webfunc; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class InvokedFunction { public Method method; public Class<?> clazz; public boolean single; public boolean cached; public boolean voided; public Object execute(WebSystemContext context) { Object refer = null; try { if (this.single != true) { refer = clazz.newInstance(); } Object[] args = new Object[]{context}; Object result = method.invoke(refer, args); return voided == true ? null : result; } catch (InstantiationException e) { e.printStackTrace(); throw new RuntimeException(e); } catch (IllegalAccessException e) { throw new RuntimeException(e); } catch (InvocationTargetException e) { throw new RuntimeException(e.getTargetException()); } } } 这个类用到了Java反射机制,其目的是根据参数,返回值,来执行需要被执行的方法。而这些内容的定义,就是事先加载好的,类的实例,方法名以及其他属性。 下面在定义一个指令类,来管理请求指令和调用方法之间的关系 package webfunc; import java.util.HashMap; import java.util.Map; public class InvokeCommand { Map<String, InvokedFunction> funcMap; public InvokeCommand() { funcMap = new HashMap<String, InvokedFunction>(); } public boolean hasFunction(String func) { return funcMap.containsKey(func); } public InvokedFunction getFunction(String func) { return InvokeCommand.this.funcMap.get(func); } public void put(String func, InvokedFunction invFunc) { this.funcMap.put(func, invFunc); } } 在这个类中我们维护一个map,这个map管理请求指令与被调用对象的关系。比如指令为personVerify,其对应的被调用方法就是public ResponseData personVerifyMethod(WebSystemContext context)。 小零件都准备好了,我们就要在系统启动的时候加载这些注解和方法,等待被系统调用 package webfunc; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.util.HashMap; import java.util.Map; public class ServiceContext { public static Map<String, InvokeCommand> cmmdMap; private static ServiceContext context; private ServiceContext() { cmmdMap = new HashMap<String, InvokeCommand>(); try{ //...preload the Commands from xml file... //the business class String classStr = "com.test.example.Business.UserAction"; //Request Command String commandStr = "personVerify"; this.parseWebModule(Class.forName(classStr), commandStr); }catch(Exception e){ e.printStackTrace(); } } public static ServiceContext getContext() { if (context == null) { context = new ServiceContext(); } return ServiceContext.context; } public boolean hasCommand(String cmmd) { return cmmdMap.containsKey(cmmd); } public InvokeCommand getCommand(String cmmd) { return this.cmmdMap.get(cmmd); } public void parseWebModule(Class<?> clz, String code) { Class<RequestFunction> antClass = RequestFunction.class; for (Method method : clz.getMethods()) { int modify = method.getModifiers(); if (Modifier.isPublic(modify)) { RequestFunction webfunc = null; if (method.isAnnotationPresent(antClass)) { webfunc = method.getAnnotation(antClass); if (code.equals(webfunc.action())) { InvokeCommand proxy = null; if (!cmmdMap.containsKey(code)) { proxy = new InvokeCommand(); cmmdMap.put(code, proxy); } InvokedFunction webmethod = null; webmethod = new InvokedFunction(); webmethod.clazz = clz; webmethod.method = method; webmethod.cached = webfunc.cached(); webmethod.single = Modifier.isStatic(modify); Class<?> returnType = method.getReturnType(); webmethod.voided = returnType.equals(Void.class); proxy = cmmdMap.get(code); proxy.put(code, webmethod); } } } } } } 这个类中,我们通过配置文件加载了业务执行类和业务执行方法。把他们提前加载到内存,等请求到达时,就可以判断该请求命令是否合法。如果合法,就可以调用与其对应的方法。然后返回响应给客户端,这里也用到了JAVA的反射机制。 这里的业务执行类和调用命令应该全部配置在文件中统一加载。现在大多数的框架已经改变了模式,这样也会造成配置文件的臃肿。现在大多数框架都是检索Annotation,利用Java的反射机制解析其内容。这里只是用例子说明Annotation和反射机制是如果帮助我们开发Java框架的。 这一套东西既可以用在Web框架中,也可以用在C/S结构的接口平台中,非常实用。 文章导航 JAVA カスタム アノテーションを使用して、エラー解析クラスと定義クラスを構築します-Java Annotationの実用化(1) Using Java Annotation and Java reflection mechanism to build a Web framework – the practical application of Java Annotation and Java reflection (2)