请教大家使用 Java 反射封装 Servlet 的问题

2016-05-17 19:16:23 +08:00
 onice

如果一个请求对应一个 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 怎么可以?

4260 次点击
所在节点    Java
14 条回复
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()
sagnitude
2016-05-17 20:19:57 +08:00
murmur
2016-05-17 20:20:27 +08:00
你都想到了这一层了 说明你需要 springmvc 了
KuroNekoFan
2016-05-17 20:26:08 +08:00
aop
onice
2016-05-17 20:35:46 +08:00
@sagnitude 已附上我的 Demo ,请指教
Comdex
2016-05-17 20:45:16 +08:00
用 getDeclaredMethod 和 method.setAccessible(true)
sagnitude
2016-05-17 20:46:08 +08:00
@onice 你这个 Base 和 Sub 没有继承关系啊……
而且
```
Base base = new Base();
```
应该是
```
Base base = new Sub();
```
然后就可以了……
sagnitude
2016-05-17 20:47:31 +08:00
@onice 修正,我看错了…是继承的,拷代码的时候漏了……
Comdex
2016-05-17 20:48:22 +08:00
@sagnitude 同 7 楼,这是个 bug
onice
2016-05-17 21:49:44 +08:00
@sagnitude 看你这么写,瞬间秒懂了。。。
pixstone
2016-05-17 22:32:31 +08:00
= =为什么要用反射?直接 一个 Map ,
Key 为 Method , Value 为 执行流程的 Handler 对象即可。
至于 Map 的构建可以用 Spring 注入,不用人工写。
当然用上了 Spring 就直接 SpringMVC 吧,基本上就是你设想的方案来处理的。只是具体实现上用 Spring 的 IoC 来注入,不是直接走原始的反射方案。
sunyue
2016-05-18 10:21:50 +08:00
感觉楼主这个思路和 DWR 没什么区别啊?
zhen14
2016-06-08 17:09:49 +08:00
最近的一个功能中跟 lz 用相同的思路
@sunyue DWR 有什么优势吗?
sunyue
2016-06-20 19:33:33 +08:00
@zhen14 简单说就是直接使用 js 代码调用后台代码,在代码的书写上是比较方便的。主要就是这一点吧。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/279325

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX