文章目录
- 一 方法句柄
- 二 如何使用方法句柄
- 三 核心Servlet的大致框架构建
一 方法句柄
方法句柄是Java7的JSR 292版本中新增的功能,我简单介绍下。方法句柄和反射是较为类似的,但是两者的使用场景有所却别,相对而言反射速度慢,安全性差,但是使用更简单,而方法句柄执行速度快,但使用上也较为麻烦。
当我设想通过的一个通用的Servlet来将所有请求进行分发的时候,我首先想到了这个机制,作为Web项目,服务端的响应速度还是很重要的,所以我没有选择通过过滤器或者其他设计方案,仅仅是因为这个轻量级的方法句柄可以满足我当下的所有需求。
二 如何使用方法句柄
还是做一个简单的样例,最后再将如何整合到我们的核心Servlet中。
方法句柄和反射的Method类似,我们想一下Method的invoke是如何工作的?需要确定方法归属类型,需要确定方法签名,有可能需要确定方法的返回类型,当然还有方法的访问修饰符。所以简单介绍下方法句柄执行流程,更为具体的介绍请自行参考官方文档:
- 创建MethodType对象,指定方法的签名;
- 在MethodHandles.Lookup中查找类型为MethodType的MethodHandle;
- 传入方法参数并调用MethodHandle.invoke或者MethodHandle.invokeExact方法。
更为直观的看一下测试代码吧:
package com.bubbling.test;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
public class Test
{
public static void main(String[] args)
{
Lookup lookup = MethodHandles.lookup();
/*
* 获得方法句柄通过java.lang.invoke.MethodHandles.Lookup类来完成
* findConstructor就是查找构造器的
* findVirtual就是查找一般函数的(同invokeVirtual)
* findStatic 就是查找静态方法的(同invokeStatic)
* findSpecial查找私有方法的
* 获取属性的话通过findGetter或者fingStaticGetter就可以了
*/
MethodHandle methodHandler;
try
{
methodHandler = lookup.findVirtual(A.class, "test1", MethodType.methodType(void.class));
methodHandler.invoke(new A());
methodHandler = lookup.findStatic(A.class, "test2", MethodType.methodType(String.class));
String str = (String) methodHandler.invoke();
System.out.println(str);
}
catch (NoSuchMethodException e)
{
e.printStackTrace();
}
catch (IllegalAccessException e)
{
e.printStackTrace();
}
catch (Throwable e)
{
e.printStackTrace();
}
}
}
class A extends Test
{
public void test1()
{
System.out.println(1);
}
public static String test2()
{
return 2 + "";
}
}
上例的运行输出如下:
这里没有列举其他详细方法,有兴趣的朋友可以参阅API手册,里面有详细的说明。
三 核心Servlet的大致框架构建
按照之前的设计思路,我们需要将所有请求通过核心Servlet分发到具体的Servlet处理类中,其实现原理就是第一小节提到的方法句柄,那么我们需要进行一些约定设计了:
- 所有请求均通过IServlet处理;
- 所有Servlet均派生自IServlet;
- IServlet实现类获取请求、应答对象及请求参数等操作均需要通过IServlet提供的接口处理;
- IServet实现类的每一个方法应对一个请求的处理过程;
- IServelt实现类的每一个方法声明都为pubilc void,且方法参数列表为空
所以IServlet的大致结构如下:
package com.bubbling.servlet.base;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import com.bubbling.common.Constant;
import com.bubbling.util.GsonUtil;
import com.google.gson.Gson;
/**
* @author 胡楠
*
* 所有Servlet均需要自该类派生,并且需实现处理请求映射的获取方法,派生类的所有方法访问类型按规范必须声明为public,
* 且返回值为void
*
*/
public abstract class IServlet extends HttpServlet
{
private static final long serialVersionUID = 1L;
private HttpServletRequest request;
private HttpServletResponse response;
private HttpSession session;
private IResponse result = new IResponse();
public IResponse getWebResponse()
{
return result;
}
public HttpServletRequest getRequest()
{
return request;
}
public HttpServletResponse getResponse()
{
return response;
}
public HttpSession getSession()
{
return session;
}
public String getParam(String name)
{
return request.getParameter(name);
}
/**
* @return kEY值为请求参数action值,VALUE值为处理该请求的方法名
*/
protected abstract Map<String, String> getMethodMap();
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
{
this.request = request;
this.response = response;
this.session = request.getSession(true);
if (this.result == null)
{
this.result = new IResponse();
}
process();
}
private void process() throws IOException
{
}
private void processAction() throws Throwable
{
Map<String, String> methodMap = getMethodMap();
String action = request.getParameter("action");
if (!methodMap.containsKey(action))
{
setWebResponseInvalidAction();
}
else
{
MethodHandles.lookup().findVirtual(getClass(), methodMap.get(action), MethodType.methodType(void.class))
.invoke(this);
}
}
}