如果一个请求对应一个 Servlet 的话,工程大了, Servlet 的类就会很多,不方便管理。 虽然可以使用条件判断将多个请求处理写到一个 Servlet 类中,但这样代码太不美观。
Servlet 的请求是由 service 方法接收,然后再根据请求的类型转给 doGet 和 doPost 等方法。今天看到一种基于反射的写法:这种写法覆盖了 service 方法,在Service 方法中利用 Java 反射的机制改变请求的转向。
贴代码:
package com.hack4b.servlet; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * 封装 Servlet ,完成对任意用户的请求进行处理 */ public class BaseServlet extends HttpServlet { /** * */ private static final long serialVersiOnUID= -1521560009181973222L; @Override protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { //设置编码 req.setCharacterEncoding("UTF-8"); //定义用户请求参数 String v =req.getParameter("v"); //定义响应的方法 Method method = null; try { //得到方法 method = this.getClass().getMethod(v, HttpServletRequest.class,HttpServletResponse.class); } catch (NoSuchMethodException | SecurityException e) { System.out.println("反射错误!程序已退出!"); e.printStackTrace(); return; } try { //获取方法的执行结果 String result = (String)method.invoke(this,req,resp); //处理结果 if(result!=null&&!result.trim().isEmpty()){ int index = result.indexOf(":"); String param = result.substring(0,index); String path = result.substring(index+1); if(param.equals("f")){ req.getRequestDispatcher(path).forward(req, resp); }else if(param.equals("r")){ resp.sendRedirect(path); } } } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { System.out.println("方法执行失败!"); e.printStackTrace(); } } }
其他的Servlet就继承这个类,在访问 Servlet 的时候加上参数,例如: http://localhost:8080/users.do?v=queryId 其中, queryId 是继承上述代码的一个子类中的方法。
按照这么写的话,这样子实际上是使用 Java 的反射机制去调用了子类的方法。
于是我自写了一个 Demo , Demo 中由两个类,一个是 Base 基类,一个是继承 Base 的 Sub 派生类,然后再进行反射机制的调用,结果发现使用 Java 反射不能去调子类的方法。 抛出异常: java.lang.NoSuchMethodException: com.hack4b.test.Base.testSubMethod() 意思就是说找不到 Base 子类的方法。
我就纳闷了,,既然反射不能去调派生类的方法,那么那个用反射实现的 Servlet 怎么可以?
附上我自己写的Demo代码:
package com.hack4b.test; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class Base { public void m01(){ try { Method m = this.getClass().getMethod("testSubMethod"); m.invoke(this); } catch (NoSuchMethodException | SecurityException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
package com.hack4b.test; public class Sub extends Base { public void testSubMethod(){ System.out.println("testMethod runed."); } }
package com.hack4b.test; public class Main { public static void main(String[] args) { Base base = new Base(); base.m01(); } }
![]() | 1 sagnitude 2016-05-17 20:18:08 +08:00 1. demo 呢? 2. 反射可以调子类方法 3. 如果你用的是 getMethod ,试试 getDeclaredMethod 4. 如果你用的不是 this.getClass(),改成这个 5. 别忘了加上 method.setAccessible(true) 6. this.getClass()要求在实例方法里运行,如果是 static 方法,需要想办法得到子类的 Class 对象,比如传进来一个 instance 再 getClass(),或者用泛型,然后 getGenericSuperclass(),然后 getActualTypeArguments()然后 getRawType() |
![]() | 2 sagnitude 2016-05-17 20:19:57 +08:00 |
![]() | 3 murmur 2016-05-17 20:20:27 +08:00 你都想到了这一层了 说明你需要 springmvc 了 |
4 KuroNekoFan 2016-05-17 20:26:08 +08:00 via iPhone aop |
![]() | 6 Comdex 2016-05-17 20:45:16 +08:00 用 getDeclaredMethod 和 method.setAccessible(true) |
![]() | 7 sagnitude 2016-05-17 20:46:08 +08:00 ![]() @onice 你这个 Base 和 Sub 没有继承关系啊…… 而且 ``` Base base = new Base(); ``` 应该是 ``` Base base = new Sub(); ``` 然后就可以了…… |
![]() | 11 pixstone 2016-05-17 22:32:31 +08:00 = =为什么要用反射?直接 一个 Map , Key 为 Method , Value 为 执行流程的 Handler 对象即可。 至于 Map 的构建可以用 Spring 注入,不用人工写。 当然用上了 Spring 就直接 SpringMVC 吧,基本上就是你设想的方案来处理的。只是具体实现上用 Spring 的 IoC 来注入,不是直接走原始的反射方案。 |
12 sunyue 2016-05-18 10:21:50 +08:00 感觉楼主这个思路和 DWR 没什么区别啊? |