`
xifangyuhui
  • 浏览: 186047 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

java代理(Proxy)模式浅析

阅读更多

下面的代码实现一个简单的代理类,代码来自《java与模式》,该例子的任务是为一个Vector对象提供一个代理对象,当Vector的任何方法被调用之前和调用之后,分别打印出两条信息,这表明这个代理对象有能力截获和控制这个Vector对象。

 

/*
 * 实现一个简单的代理类,代码来自《java与模式》该例子
 * 的任务是为一个Vector对象提供一个代理对象,当Vector
 * 的任何方法被调用之前和调用之后,分别打印出两条信息,
 * 这表明这个代理对象有能力截获和控制这个Vector对象。
 */
public class VectorProxy implements InvocationHandler{
	//包含被代理的对象,这里是一个Vector
	private Object targetObj;
	//为被代理对象设置一个get方法,这里只是我用来测试所用
	public Object getTargetObj() {
		return targetObj;
	}
	//构造方法,并接受被代理对象作为参数
	public VectorProxy(Object targetObj) {
		this.targetObj = targetObj;
	}
	//一个静态工厂方法,用来获得代理对象,传递被代理对象作为参数
	public static Object factory(Object obj) {
		Class clazz = obj.getClass();
		//调用newProxyInstance方法得到一个代理对象,这个方法下面会详述
		Object proxy =  Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new VectorProxy(obj));
		return proxy;
	}
	//实现InvocationHandler接口的invoke方法,该方法会被自动调用
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("before invoke:" + method.getName()); //调用被代理对象某方法之前执行一句打印
		if(args != null) {
			for(Object o:args) 
				System.out.println(o);
		}
		//通过代理对象获得被代理对象,首先调用Proxy的静态方法getInvocationHandler,并传递代理对象获得代理类中
		//关联的InvaocationHandler的实现类对象,再接着调用我们上面定义的获取被代理对象的get方法
		Object tarObj = ((VectorProxy)(Proxy.getInvocationHandler(proxy))).getTargetObj();
		System.out.println(tarObj == targetObj);  //测试通过上面方法获得的被代理对象是否就是当前VectorProxy实例中的对象
		Object resultObj = method.invoke(tarObj, args); //这里直接传递targetObj即可,对被代理对象调用某方法,并传递参数
		System.out.println("after invoke:" + method.getName());  //调用被代理对象某方法之后执行一句打印
		return resultObj;
	}

	public static void main(String[] args) {
		List v = null;
		//new Vector(10)是被代理对象,它被传入InvocationHandler中,作为成员变量,InvocationHandler的实现类也会作为Proxy的成员变量
		v = (List) factory(new Vector(10));   
		//对代理对象调用被代理对象所拥有的方法,此时会自动调用Proxy中关联的VectorProxy实例的invoke方法
		v.add("NEW");
		System.out.println(v.get(0));
	}
}
 

上面的代码中我们创建类VectorProxy并实现InvocationHandler接口,当然它需要实现InvocationHandler接口中的invoke方法了。

我们首先需要创建一个代理对象,并在代理对象中指定被代理对象,以及指定被代理对象的所有实现接口:

Class clazz = obj.getClass(); //obj为被代理对象

Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), new VectorProxy(obj));  //传递三个参数:被代理对象的类加载器,被代理对象所实现的接口数组以及一个InvocationHandler实现类对象,注意这个实现类对象中包含了被代理对象。

 

现在我们就用生成的代理对象来代替被代理对象,直接对代理对象进行操作。

当Client需要调用被代理对象中的方法时,这些方法是它所实现接口中的方法( getInterfaces() ),此时我们是对代理对象调用这些方法,代理对象便会自动调用代理对象中相关联的InvocationHandler实现类的invoke方法,即我们实现的

public Object invoke(Object proxy, Method method, Object[] args)

我们可以在invoke方法中实现我们需要的逻辑,包括调用被代理对象对应的方法:

 

method.invoke(targetObject,args) //targetObject为被代理对象,被代理对象是作为InvocationHandler实现类的成员变量,args为传递给方法的参数,

 

还可以在调用被代理对象相关方法之前和之后执行某些操作。

当我们对代理对象执行某些操作,这些操作和对被代理对象执行的操作一样,其实我们的本意也是对被代理对象进行某些操作,在本例中,即在vector中添加,删除,获取对象等。此时会自动调用代理对象中相关联的InvocationHandler接口的实现类的invoke方法,同时将代理对象,被调用的方法以及方法的参数作为参数传递给invoke,因此我们便可以在invoke中实现我们需要的操作。

 

JDK 中具体的动态代理类是怎么产生的呢?

1. 产生代理类$Proxy0

执行了 Proxy. newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)

将产生$Proxy0 类,它继承Proxy 对象,并根据第二个参数,实现了被代理类的所有接口,自然就可以生成接口要实现的所有方法了(这时候会重写hashcodetoStringequals 三个方法),但是还没有具体的实现体;

2.    将代理类$Proxy0 类加载到JVM

这时候是根据 Proxy. newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 它的第一个参数---- 就是被代理类的类加载器,把当前的代理类加载到JVM

3.    创建代理类$Proxy0 类的对象

调用的$Proxy0 类的$Proxy0InvocationHandler )构造函数,生成$Proxy0 类的对象

参数就是 Proxy. newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 它的第三个参数

这个参数就是我们自己实现的InvocationHandler 对象,我们知道InvocationHandler 对象中组合加入了代理类代理的接口类的实现类;所以,$Proxy0 对象调用所有要实现的接口的方法,都会调用InvocationHandler 对象的invoke ()方法实现;

4.    生成代理类的class byte

动态代理生成的都是二进制class 字节码

----------------------------------------------------------------

我们下面来简单看一下Proxy类,Proxy类位于java.lang.reflect中, 首先看看它的成员变量和构造函数:

 private final static Class[] constructorParams = { InvocationHandler.class };
protected InvocationHandler h;

 private Proxy() {
    }

 protected Proxy(InvocationHandler h) {
	this.h = h;
    }

上面的成员变量和第二个构造函数相信大家应该不会陌生吧,在一个Proxy实例中包含了一个InvocationHandler的实例。

接下来我们再看Proxy类的静态方法 newProxyInstance

 public static Object newProxyInstance(ClassLoader loader,
					  Class<?>[] interfaces,
					  InvocationHandler h)
	throws IllegalArgumentException
    {
	if (h == null) {
	    throw new NullPointerException();
	}             
       //通过被代理的类加载器和接口数组来动态生成一个代理类Class
       Class cl = getProxyClass(loader, interfaces);  
        try {  
//通过Class的getConstructor方法获得相关的Constructor对象,注意传递的参数是一个Class数组
            Constructor cons = cl.getConstructor(constructorParams);
//利用Constructor创建一个代理类实例,并将InvocatioHandler实例作为参数传递给它
	    return (Object) cons.newInstance(new Object[] { h });
	} catch (NoSuchMethodException e) {
	    throw new InternalError(e.toString());
	} 
        //省略相关代码
    }

 接下来关注更重要的getProxyClass方法:

public static Class<?> getProxyClass(ClassLoader loader, 
                                         Class<?>... interfaces)
	throws IllegalArgumentException
    {
	if (interfaces.length > 65535) {
	    throw new IllegalArgumentException("interface limit exceeded");
	}  //这段代码大家应该都能看懂,规定实现的借口不能超过65535个
	Class proxyClass = null;
//定义一个接口名字数组和一个接口Set
	String[] interfaceNames = new String[interfaces.length];
	Set interfaceSet = new HashSet();	// for detecting duplicates
//遍历接口数组,将通过getName方法获得接口的名字,并通过被代理对象的类加//载器加载接口生成Class对象,即生成Class字节码
	for (int i = 0; i < interfaces.length; i++) {
	    String interfaceName = interfaces[i].getName();
	    Class interfaceClass = null;
	    try {
	interfaceClass = Class.forName(interfaceName, false, loader);
	} catch (ClassNotFoundException e) {
	}
	    if (interfaceClass != interfaces[i]) {
	        ...
	    }
	    if (!interfaceClass.isInterface()) {
		...
	    }
	 
	    if (interfaceSet.contains(interfaceClass)) {
		...
	    }
//将接口字节码Class对象保存到Set中,并将接口名保存到接口名数组中
	    interfaceSet.add(interfaceClass);
	    interfaceNames[i] = interfaceName;
	}
//将接口名字数组转化为一个List
	Object key = Arrays.asList(interfaceNames);
//loaderToCache也是一个Map.它的key是classloader,对应的value是对应的缓存,也是一个HashMap.他把对应的不同的classloader放到loaderToCache里,如果下次还要调用这个方法创建代理,并传入的是同一个classloader,那么可以直接从cache里取..增加速度.当然,如果没有,则创建一条记录,放到loaderToCache里
	Map cache;
	synchronized (loaderToCache) {
	    cache = (Map) loaderToCache.get(loader);
	    if (cache == null) {
		cache = new HashMap();
		loaderToCache.put(loader, cache);
	    }
	}	
	synchronized (cache) {
	    do {
//这里从cache里获取对应的Object..第一次执行的话,明显获取到的是Null..key表示的是用接口名字转换而来的list.
		Object value = cache.get(key);
		if (value instanceof Reference) {
		    proxyClass = (Class) ((Reference) value).get();
		}
		if (proxyClass != null) {
		    // proxy class already generated: return it
		    return proxyClass;
		} else if (value == pendingGenerationMarker) {
		    // proxy class being generated: wait for it
		    try {
			cache.wait();
		    } catch (InterruptedException e) {
			
		    }
		    continue;
		} else {
		   
		    cache.put(key, pendingGenerationMarker);
		    break;
		}
	    } while (true);
	}

	try {
	    String proxyPkg = null;	// package to define proxy class in

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

	    if (proxyPkg == null) {	// if no non-public proxy interfaces,
		proxyPkg = "";		// use the unnamed package
	    }

	    {
	
		long num;
		synchronized (nextUniqueNumberLock) {
		    num = nextUniqueNumber++;
		}
		String proxyName = proxyPkg + proxyClassNamePrefix + num;
		
		byte[] proxyClassFile =	ProxyGenerator.generateProxyClass(
		    proxyName, interfaces);
		try {
		    proxyClass = defineClass0(loader, proxyName,
			proxyClassFile, 0, proxyClassFile.length);
		} catch (ClassFormatError e) {
		  
		    throw new IllegalArgumentException(e.toString());
		}
	    }
	    // add to set of all generated proxy classes, for isProxyClass
	    proxyClasses.put(proxyClass, null);

	} finally {
	
	    synchronized (cache) {
		if (proxyClass != null) {
		    cache.put(key, new WeakReference(proxyClass));
		} else {
		    cache.remove(key);
		}
		cache.notifyAll();
	    }
	}
	return proxyClass;
    }
 
1
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics