0
点赞
收藏
分享

微信扫一扫

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+时序图)

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

通过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");
		    }
		}
	    }


 

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

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

举报

相关推荐

0 条评论