1. 程式人生 > >完整JavaWeb專案筆記 第五部分-通過方法控制代碼實現動態方法呼叫

完整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);
		}
	}
}