以反射的方式實現的定向代理

package question3;

import java.lang.reflect.Method;
import java.util.ArrayList;

/*
 * 	寫一個ArrayList類的代理,其內部實現和ArrayList中完全相同的功能,
 * 	並可以計算每個方法運行的時間。
 * 
 *  解題方式二
 *  1.反射機制實現代理調用
 *  2.實現統一的代理工廠方法來實現代理的創建
 *  3.爲該方法的耗時計算實現線程安全,以精度爲納秒計算
 *  4.爲目標ArrayList實現線程安全
 *  
 *  優點:摒棄了第一種方式的大量代碼創建量
 *  	  相對於第一種方式,可以調用ArrayList的上層
 *  	  方法和本地方法,而不僅是上層方法
 *  缺點:反射方式總歸還是會導致目標方法調用耗時多一些
 *  	  而invoke方法的隱式類型方式,不熟悉Arraylist
 *  	  的話很容易出錯,同時這樣的代理侷限性很明顯,
 *  	  僅僅只支持ArrayList
 *  
 *  注:1秒=1 000 000 000納秒 jdk api中以毫微秒錶示納秒
 */
public class ArrayListProxy_2<E>
{
	@SuppressWarnings("unchecked")
    public static void main(String[] args)
	{
		ArrayListProxy_2<String> proxy = ArrayListProxy_2.factory();
		proxy.invoke("add", new Class[]{Object.class}, new Object[]{"zhangsan"});
		proxy.invoke("size", null, null);
		
		//本行如果不註釋,會拋異常,因爲沒有這個方法
		//不過並不會導致程序終止
		//proxy.invoke("lalalala", null, null);
		
		proxy.invoke("get", new Class[]{int.class}, new Object[]{0});
	}
	
	/**
	 * 此代理的目標ArrayList,該成員只有代理類
	 * 可以持有,所以不應該暴露給用戶,而是私有
	 */
	private ArrayList<E> target = new ArrayList<E>();
	
	/*
	 * 爲該代理實現工廠方法,並私有化構造方法
	 * 實現統一的代理創建方式
	 */
	private ArrayListProxy_2(){}
	public static final <E> ArrayListProxy_2<E> factory()
	{
		return new ArrayListProxy_2<E>();
	}
	
	/**
	 * 本類的代理方法,用以實現ArrayList的所有方法的
	 * 代理調用,並統計耗時,本方法是線程安全的
	 * 
	 * <p><font color=red>代理方法並不應該因爲異常而導致程序終止(退出),
	 * 而是應該以日誌方式記錄該異常信息,以表明該代理
	 * 的使用者存在顯式的錯誤</font>
	 * 
	 * @param methodName 需要調用的方法名稱
	 * @param parameterTypes 該方法的參數類型列表
	 * @param parameters 該方法的參數列表
	 * @return 該方法的返回值;如果出現異常,並不會被拋出
	 * 		       控制檯僅以錯誤方式顯示該異常的信息,但不會
	 * 	                包括異常堆棧信息,而同時返回null
	 */
	public Object invoke(String methodName, Class<? extends Object>[] parameterTypes, Object[] parameters)
	{
		try
        {
			Object returnValue = null;
			Method method = target.getClass().getMethod(methodName, parameterTypes);
			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;
	    }
	}
}

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