Proxy模式1--JAVA中的代理实现

一。首先需要了解下面3个类的API:java系统支持的代理就是这3个类+反射来实现。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
 

 

二。下面的这段测试代码,目的就是:将一个ArrayList对象的操作进行代理,每个method前后都输出一行字符串。

核心代码是

Class clz = ArrayList.class;
Object proxyed_Object = Proxy.newProxyInstance(clz.getClassLoader(),
         clz.getInterfaces(), new MyInvocationHandle(new ArrayList(10)));

生成一个ArrayList的代理的对象。

package proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;

/**
 * DEMO:测试java中的代理
 * 
 * 代理了一个ArrayList对象,并在调用方法前后各加了一个systemout输出
 * @author wei.songw
 * 
 */
public class MyInvocationHandle implements InvocationHandler {

	//对代理对象的引用.
	private List aList;

	/**
	 * 构造器。
	 * @param list 代理对象
	 */
	public MyInvocationHandle(Object list) {
		this.aList = (List) list;
	}

	/**
	 * InvocationHandler的方法实现
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		
		//方法前调用,插入一段消息
		System.out.println("before : "+method.getName());
		
		//调用方法.
		Object object = method.invoke(aList, args);
		
		//方法后调用,插入一段消息
		System.out.println("after : "+method.getName());
		
		return object;
	}



	public static void main(String[] args) {
		//需要代理一个ArrayList对象,因此按照API构造一个Proxy对象
		//,同时也初始化了处理Proxy的MyInvocationHandle对象
		Class clz = ArrayList.class;
		Object proxyed_Object = Proxy.newProxyInstance(clz.getClassLoader(),
				clz.getInterfaces(), new MyInvocationHandle(new ArrayList(10)));
		
//TEST1:查看一下代理生成类的接口???
//		Class[] itfs = proxyed_Object.getClass().getInterfaces();
//		for (int i = 0; i < itfs.length; i++) {
//			System.out.println(itfs[i].getName());
//		}
		
		//注意!这里操作的是代理类!
		List list = (List)proxyed_Object;
		list.add(Integer.valueOf(10));
		
//TEST2:输出一下list的大小,确认add方法被调用		
//		System.out.println(list.size());
	}
}
 

输出如下:

before : add
after : add

如果将TEST2段代码去掉注释,可以看到如下输出:

before : add
after : add
before : size
after : size
1

证明add方法确实被调用了。


 三。代理模式的结构图(UML+时序图)

通过UML图可以看到代理类和被代理实际对象实现同一接口/或者一个抽象类,因此外部调用Subject,是感觉不到代理类的存在。

 

问题出现了:上面的测试代码中,被代理ArrayList对象,并未与调用者MyInvocationHandle实现同样的接口 。那是怎么实现代理模式的呢?

看Proxy类的文档,写到:

   /**
     * Returns an instance of a proxy class for the specified interfaces
     * that dispatches method invocations to the specified invocation
     * handler.  This method is equivalent to:
     * 
     *     Proxy.getProxyClass(loader, interfaces).
     *         getConstructor(new Class[] { InvocationHandler.class }).
     *         newInstance(new Object[] { handler });
     * 
* *

Proxy.newProxyInstance throws * IllegalArgumentException for the same reasons that * Proxy.getProxyClass does. * * @param loader the class loader to define the proxy class * @param interfaces the list of interfaces for the proxy class * to implement * @param h the invocation handler to dispatch method invocations to * @return a proxy instance with the specified invocation handler of a * proxy class that is defined by the specified class loader * and that implements the specified interfaces * @throws IllegalArgumentException if any of the restrictions on the * parameters that may be passed to getProxyClass * are violated * @throws NullPointerException if the interfaces array * argument or any of its elements are null, or * if the invocation handler, h, is * null */

 

返回一个实现指定接口的代理类实例,并绑定方法调用到一个指定的invocation handler.

如果将TEST1段注释去掉,可以看到这个代理对象实现了如下接口:

 java.util.List    java.util.RandomAccess     java.lang.Cloneable      java.io.Serializable

 

并且Proxy.newProxyInstance等同于

     *     Proxy.getProxyClass(loader, interfaces).
     *         getConstructor(new Class[] { InvocationHandler.class }).
     *         newInstance(new Object[] { handler });

这里是部分源码:

	    for (int i = 0; i < interfaces.length; i++) {
		int flags = interfaces[i].getModifiers();
		if (!Modifier.isPublic(flags)) {
		    String name = interfaces[i].getName();
		    int n = name.lastIndexOf('.');
		    String pkg = ((n == -1) ? "" : name.substring(0, n + 1));
		    if (proxyPkg == null) {
			proxyPkg = pkg;
		    } else if (!pkg.equals(proxyPkg)) {
			throw new IllegalArgumentException(
			    "non-public interfaces from different packages");
		    }
		}
	    }
 

 

通过时序图可以看到,外部Client和代理类打交道,而代理类在调用实际对象时可以增加一些有益的操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值