以反射的方式实现的任意代理 可以代理本地方法

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("==============================================>");
	}
}

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