代理模式——JDK动态代理实现

代理模式是常见的一种设计模式,代理模式提供了另外一种访问目标对象的方式,通过代理对象取访问目标对象,这样的话就可以在访问目标对象的前后做一些自己想要的操作,在不改变原有对象功能能前提下,实现功能的增强或扩展。实现方式有静态代理和动态代理。动态代理和静态代理的区别在于代理类生成的时机,静态代理代理类一般是我们在编码时手动实现的,然后再编译成class,而动态代理则是根据我们提供的信息在程序运行期间生成代理类。今天写的这篇文章就是关于JDK动态代理的一些内容。

JDK中已经实现了动态代理机制,其中和动态代理相关的有一个重要的接口InvocationHandler,一个重要的类Proxy。它们都在java.lang.reflect包下面。

首先看下InvocationHandler接口,接口中定义了一个invoke方法,方法中有三个参数,这三个参数的代表含义分别为代理对象、执行方法(真实对象的某一个方法)、方法参数数组。

public interface InvocationHandler {

    
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

接着看下Proxy类这个类有个很重要的方法newProxyInstance,通过调用该方法JVM会生成一个代理类并实例化一个代理对象返回。该方法同样有三个参数,这个三个参数代表的含义分别是类加载器,要实现的接口列表,InvocationHandler实例。

 public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {
        Objects.requireNonNull(h);

        final Class<?>[] intfs = interfaces.clone();
        final SecurityManager sm = System.getSecurityManager();
        if (sm != null) {
            checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
        }

       
        Class<?> cl = getProxyClass0(loader, intfs);

        try {
            if (sm != null) {
                checkNewProxyPermission(Reflection.getCallerClass(), cl);
            }

            final Constructor<?> cons = cl.getConstructor(constructorParams);
            final InvocationHandler ih = h;
            if (!Modifier.isPublic(cl.getModifiers())) {
                AccessController.doPrivileged(new PrivilegedAction<Void>() {
                    public Void run() {
                        cons.setAccessible(true);
                        return null;
                    }
                });
            }
            return cons.newInstance(new Object[]{h});
        } catch (IllegalAccessException|InstantiationException e) {
            throw new InternalError(e.toString(), e);
        } catch (InvocationTargetException e) {
            Throwable t = e.getCause();
            if (t instanceof RuntimeException) {
                throw (RuntimeException) t;
            } else {
                throw new InternalError(t.toString(), t);
            }
        } catch (NoSuchMethodException e) {
            throw new InternalError(e.toString(), e);
        }
    }

知道了以上的内容,我们就可以自己实现动态代理了。

首先我们先定义一个Sort接口,这个接口中有个sort方法,可以对整型数组进行排序。下面代码是Sort接口的定义。

public interface Sort {

	void sort(int[] array);
}

接着我们实现这个接口,实现这个接口我们采用快速排序的算法。下面代码是QuickSort的实现。

public class QuickSort implements Sort{
	

	@Override
	public void sort(int[] array) {
		
		System.out.println("执行快速排序算法");
		if (array == null) {
			return ;
		}
		if (array.length < 2) {
			return ;
		}
		quickSort(array, 0, array.length - 1);
		System.out.println("排序后");
		printArray(array);
	}
	
	private void quickSort(int[] array, int start, int end) {
		if (start >= end) {
			return ;
		}
		int  low = start;
		int height = end;
		int key = array[low];
		while (low < height) {
			while(height > low && array[height] > key) {
				height--;
			}
			array[low] = array[height];
			while(low < height && array[low] <= key) {
				low++;
			}
			array[height] = array[low];
		}
		array[low] = key;
		quickSort(array, start, low - 1);
		quickSort(array, low + 1, end);
	}
	
	/**
	 * 打印数组内容
	 * @param array
	 */
	private void printArray(int[] array) {
		for (int i : array) {
			System.out.print(i);
			System.out.print(" ");
		}
		System.out.println();
	}

}

现在我们采用动态代理的方式去计算每次调用快速排序算法的耗时。实现InvocationHandler接口,并且实现计算耗时的功能。代码如下:

public class MyInvocationHandler implements InvocationHandler{
	// 代理目标对象
	private Object target;
	
	public MyInvocationHandler(Object target) {
		this.target = target;
	}
	

	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //方法执行前,记录开始时间
		long start = System.currentTimeMillis();
                //执行目标对象的方法
		method.invoke(target, args);
                //方法执行后,记录结束时间
		long end = System.currentTimeMillis();
                //打印耗时
		System.out.println(String.format("排序耗时: %d ms", end - start));
		return null;
	}

}

实现测试类

public class Test {
	
	public static void main(String[] args) throws IOException {
               //加上这行代码可以将动态生成的代理类保存本地
		System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true"); 
               //定义待排序数组   
		int array[] = {10, 8, 12, 31, 5, 1, 7, 8, 30, 10, 15};
                //实例化一个快排算法对象
		Sort sort  = new QuickSort();
                //实例化MyInvocationHandler 对象
		MyInvocationHandler myInvocationHandler = new MyInvocationHandler(sort);
                 //获取一个代理对象
		Sort sortProxy = (Sort)Proxy.newProxyInstance(myInvocationHandler.getClass().getClassLoader(), sort.getClass().getInterfaces(), myInvocationHandler);
               // 通过代理对象调用排序算法
		sortProxy.sort(array);
	}
	

}

运行结果如下图

这就利用JDK的动态代理机制,实现了动态代理模式。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值