如果一个请求对应一个 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 1
@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 没什么区别啊?
|