以反射的方式實現的任意代理 可以代理本地方法

package question3;

import java.lang.reflect.Method;

/*
 * 	寫一個ArrayList類的代理,其內部實現和ArrayList中完全相同的功能,
 * 	並可以計算每個方法運行的時間。
 * 
 *  解題方式三
 *  1.反射機制實現代理調用
 *  2.實現統一的代理工廠方法來實現代理的創建
 *  3.爲該方法的耗時計算實現線程安全,以精度爲納秒計算
 *  4.爲目標invoke實現線程安全
 *  5.實現任意代理,不在侷限於ArrayList
 *  6.實現參數的動態識別,更精簡的參數列表
 *  
 *  優點:相對於第二種方式,將可以支持代理類型的多樣化
 *       但代理代碼方面仍然死板,對於不同功能的代理
 *       扔需要編寫額外的代理類,但相對於第1 2種,
 *       仍然可以節省大量開發時間
 *      
 *  缺點:參數類型動態識別方面仍然存在缺陷,至少來說也不是
 *       那麼廢柴,還是看亮點吧。。。
 *  
 *  注:1秒=1 000 000 000納秒 jdk api中以毫微秒錶示納秒
 */
public class ArrayListProxy_3
{
	/**
	 * 此代理的目標對象,該成員只有代理類
	 * 可以持有,所以不應該暴露給用戶,而是私有
	 */
	private Object target;
	
	/**
	 * 構造函數私有化,該代理僅可通過 {@link #factory(String)}
	 * 取得實例
	 */
	private ArrayListProxy_3(String targetType) throws ClassNotFoundException, 
	InstantiationException, IllegalAccessException
	{
		target = Class.forName(targetType).newInstance();
		System.out.println("create the target instance from "+target.getClass().getName());
	}
	
	/**
	 * 本類的工廠方法
	 * 
	 * @param targetType 目標類型,該類型應該是完整的<br>
	 *                   for example java.util.ArrayList
	 */
	public static final ArrayListProxy_3 factory(String targetType) throws ClassNotFoundException, 
	InstantiationException, IllegalAccessException
	{
		return new ArrayListProxy_3(targetType);
	}
	
	/**
	 * 本類的代理方法,用以實現ArrayList的所有方法的
	 * 代理調用,並統計耗時,本方法是線程安全的
	 * 
	 * <p><font color=red>代理方法並不應該因爲異常而導致程序終止(退出),
	 * 而是應該以日誌方式記錄該異常信息,以表明該代理
	 * 的使用者存在顯式的錯誤</font>
	 * 
	 * @param methodName 需要調用的方法名稱
	 * @param parameterTypes 該方法的參數類型列表
	 * @param parameters 該方法的參數列表
	 * @return 該方法的返回值;如果出現異常,並不會被拋出
	 * 		       控制檯僅以錯誤方式顯示該異常的信息,但不會
	 * 	                包括異常堆棧信息,而同時返回null
	 */
	public Object invoke(String methodName, Object... parameters)
	{
		try
        {
			Object returnValue = null;
			Method method = target.getClass().getMethod(methodName, getParameterTypes(parameters));
			long taken = 0;
			/*
			 * 同步實現的目標方法調用以及耗時統計
			 */
			synchronized (target)
            {
				if(null != methodName)
				{
					taken = System.nanoTime();
					returnValue = method.invoke(target, parameters);
			        taken = System.nanoTime() - taken;
				}
            }
			/*
			 * 控制檯輸出目標方法調用的詳細信息,包括報名,類名,方法名
			 * 以及實參的參數列表(傳入的實際參數列表),數組不在此列。。。
			 * 並輸出返回值和耗時
			 */
	        System.out.print(target.getClass().getName()+"."+method.getName()+"(");
	        if(null != parameters)
		        for (int i = 0; i < parameters.length; i++)
	            {
		        	System.out.print(parameters[i]);
		            if(i != parameters.length - 1)
		            	System.out.print(", ");
		        }
	        System.out.println(") return "+returnValue+"      times taken by "+taken+" ns");
	        /*
	         * 將返回值返回給使用者
	         */
	        return returnValue;
        }
        catch (Exception e)
        {
        	/*
        	 * 木有用e.printStackTrace(),運行時異常會導致程序掛掉
        	 * 所以僅以錯誤方式輸出,這裏應該是需要寫進log裏面,log4j
        	 * 找不到了。。。(┬_┬)
        	 * 
        	 */
        	System.out.flush();
        	System.err.println(e.getClass().getName()+":"+e.getMessage());
        	System.err.flush();
        	return null;
	    }
	}
	
	/**
	 * 根據參數自動識別類型
	 * 
	 * <p>該方法對於範型實例還可以,因爲都提供最基本的
	 * Object元素訪問,其他的實例會發生一些強轉異常
	 * 
	 * <p>本方法是爲了實現invoke方法的便捷使用,但會
	 * 額外消耗調用時間,降低效率
	 */
	@SuppressWarnings("unchecked")
    public Class<? extends Object>[] getParameterTypes(Object[] parameters) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException
	{
		if(parameters != null)
		{
			Class[] class_array =  new Class[parameters.length];
			for (int i = 0; i < class_array.length; i++)
	        {
				//如果該參數的類型是基本類型,那麼保持原類型
				if(parameters[i].getClass().isPrimitive())
		        	class_array[i] = parameters[i].getClass();
				//如果爲包裝類型則轉換成基本類型
				//該處理是針對的自動裝箱功能
				else if(parameters[i] instanceof Number)
					class_array[i] = (Class) parameters[i].getClass().getField("TYPE").get(parameters[i]);
				//否則以Object類型傳入
				else
					class_array[i] = Object.class;
				//其實還差一步是處理添加集合的方式
				//這裏的添加集合會走參數爲Object的方法
	        }
			return class_array;
		}
		else
			return null;
	}
	
	public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException
	{
		/*
		 * 測試ArrayList的部分
		 */
		ArrayListProxy_3 proxy;
		proxy = ArrayListProxy_3.factory("java.util.ArrayList");
		proxy.invoke("add", "qqq");
		proxy.invoke("size", null);
		proxy.invoke("get", 0);
		proxy.invoke("remove", 0);
		System.out.println("==============================================>");
		
		/*
		 * 測試Linkedlist的部分
		 */
		proxy = ArrayListProxy_3.factory("java.util.LinkedList");
		proxy.invoke("add", "aaa");
		proxy.invoke("size", null);
		proxy.invoke("get", 0);
		proxy.invoke("remove", 0);
		System.out.println("==============================================>");
		
		/*
		 * 測試treemap
		 */
		proxy = ArrayListProxy_3.factory("java.util.TreeMap");
		proxy.invoke("put", "asd","efg");
		proxy.invoke("remove","asd");
		proxy.invoke("get", "asd");
		proxy.invoke("size", null);
		System.out.println("==============================================>");
	}
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章