完整JavaWeb项目笔记 第五部分-通过方法句柄实现动态方法调用

一 方法句柄

  方法句柄是Java7的JSR 292版本中新增的功能,我简单介绍下。方法句柄和反射是较为类似的,但是两者的使用场景有所却别,相对而言反射速度慢,安全性差,但是使用更简单,而方法句柄执行速度快,但使用上也较为麻烦。

  当我设想通过的一个通用的Servlet来将所有请求进行分发的时候,我首先想到了这个机制,作为Web项目,服务端的响应速度还是很重要的,所以我没有选择通过过滤器或者其他设计方案,仅仅是因为这个轻量级的方法句柄可以满足我当下的所有需求。

二 如何使用方法句柄

  还是做一个简单的样例,最后再将如何整合到我们的核心Servlet中。

  方法句柄和反射的Method类似,我们想一下Method的invoke是如何工作的?需要确定方法归属类型,需要确定方法签名,有可能需要确定方法的返回类型,当然还有方法的访问修饰符。所以简单介绍下方法句柄执行流程,更为具体的介绍请自行参考官方文档:

  1. 创建MethodType对象,指定方法的签名;
  2. 在MethodHandles.Lookup中查找类型为MethodType的MethodHandle;
  3. 传入方法参数并调用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处理类中,其实现原理就是第一小节提到的方法句柄,那么我们需要进行一些约定设计了:

  1. 所有请求均通过IServlet处理;
  2. 所有Servlet均派生自IServlet;
  3. IServlet实现类获取请求、应答对象及请求参数等操作均需要通过IServlet提供的接口处理;
  4. IServet实现类的每一个方法应对一个请求的处理过程;
  5. 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);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/o983950935/article/details/85340388