`
xifangyuhui
  • 浏览: 188980 次
  • 性别: 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
分享到:
评论

相关推荐

    JAVA 通过proxy代理方式访问internet资源

    JAVA 通过proxy代理方式访问internet资源,

    代理模式java代码 Proxy(4)

    在Java中,代理模式可以通过多种方式实现,包括静态代理和动态代理。 在提供的文件列表中,我们可以看到以下几个关键类: 1. `ProxyDisplay`:这个名字暗示了它可能是代理模式中的代理类,用于代表或代替某个实际...

    从房屋买卖看 java proxy 模式

    总的来说,Java 代理模式是通过代理类来增强或扩展目标类功能的一种设计模式,尤其适用于需要在调用前后添加额外逻辑的场景。通过深入理解代理模式和其在房屋买卖场景中的应用,我们可以更好地掌握这一重要的设计...

    java 实现HTTP PROXY

    Java实现HTTP PROXY是一个常见的需求,特别是在开发网络应用或者测试环境中,我们可能需要通过代理服务器转发HTTP请求。本文将深入探讨如何使用Java编程语言来创建一个HTTP代理服务器,并且会涉及相关的源码分析。 ...

    代理模式java代码 Proxy(1)

    在Java中实现代理模式,通常有两种方式:静态代理和动态代理。 首先,我们来看静态代理。静态代理是通过创建一个代理类来实现对目标对象的代理,这个代理类和目标类具有相同的接口,代理类在调用目标对象方法时可以...

    代理模式java代码 Proxy(5) 2个代理类

    在这个主题“代理模式java代码 Proxy(5) 2个代理类”中,我们可以理解为将介绍两种不同的代理类实现。 1. 静态代理 在静态代理中,我们需要创建一个接口,然后让目标对象和代理对象都实现这个接口。代理类会持有...

    proxy.rar java三种代理模式源码

    总结来说,"proxy.rar"压缩包提供了Java编程中三种代理模式的源代码实例,通过学习这些代码,开发者可以深入理解代理模式的原理和实现,同时掌握泛型在实际项目中的应用。对于提高代码的可扩展性和可维护性,这些都...

    java实现Proxy例子

    我自己用eclipse写的java代码,可以直接用eclipse导入,也可以直接用java -jar proxy_sample.jar执行 代码量很小,尽量通过注释进行说明 本例实现了InvocationHandler...在研究代理模式(Proxy模式)的朋友可以交流一下

    利用JAVA代理Proxy机制实现spring对ibaits的MapperScannerConfigurer功能

    利用JAVA代理Proxy机制实现spring对ibaits的MapperScannerConfigurer功能 详细:http://blog.csdn.net/wq105032007067/article/details/8812598

    Java代理模式Java动态代理

    ### Java代理模式与Java动态代理详解 #### 一、代理模式概述 代理模式是一种软件设计模式,它在客户端和目标对象之间提供了一种间接层。这种模式的主要目的是控制客户端对目标对象的访问,并且可以在不修改原有...

    java Proxy 动态代理

    Java的动态代理是一种强大的设计模式,它允许在运行时创建具有特定行为的代理对象,这些对象可以代替原对象执行某些任务。动态代理机制是Java语言提供的一种反射特性,主要用于实现AOP(面向切面编程)或者对现有...

    浅析Java设计模式【3】——代理.pdf

    ### 浅析Java设计模式【3】——代理 #### 一、代理模式概述 代理模式是一种行为型设计模式,主要用于在客户端与目标对象之间起到一个中介的作用,通过代理对象来控制对目标对象的访问。代理模式的核心在于它可以...

    java proxy demo 代理类的运用demo

    Java代理类是面向切面编程(AOP)的一种实现方式,它允许我们在不修改原有代码的情况下,为已有的对象提供额外的功能。在这个“java proxy demo”中,我们将深入探讨如何利用Sun JDK API来创建和使用Java动态代理。 ...

    Proxy 模式学习代码

    Proxy模式是一种设计模式,它允许我们为一个对象创建一个代理对象,这个代理对象在客户端和目标对象之间起到中介的作用。这种模式在软件工程中广泛应用,主要用于控制对真实对象的访问,提供额外的功能,如日志、...

    Java 静态代理模式

    Java静态代理模式是一种设计模式,它允许我们为一个对象提供一个代理,以便增强或扩展其功能,...然而,由于其存在的局限性,如需更灵活的代理机制,可以考虑使用Java的动态代理模式(如Java.lang.reflect.Proxy)。

    Java设计模式——代理设计模式(静态代理和动态代理)

    在Java编程中,设计模式是一种解决常见问题的模板或最佳实践,它可以帮助开发者编写更加灵活、可维护和可扩展的代码。代理设计模式是其中的一种,它的主要作用是在...在实际开发中,应根据项目需求选择合适的代理模式。

    JAVA设计模式之代理模式实例

    在本实例中,我们将深入探讨Java中的代理模式及其应用。 代理模式的核心思想是为一个对象创建一个代理对象,这个代理对象在客户端和目标对象之间起到中介的作用。它可以控制目标对象的访问,也可以在调用目标对象的...

    java代理模式

    Java代理模式是一种设计模式,它在面向对象编程中扮演着重要的角色,主要目的是为了在不修改原有对象的基础上,为对象添加额外的功能或者控制对对象的访问。代理模式的核心思想是通过代理类来间接调用目标类的方法,...

    Java_ProxyServer.rar_Java ProxyServer_java proxy server

    在Java_ProxyServer.rar中,"实例55"可能是包含具体代码实现的示例,这个实例可以作为学习和参考的对象,通过阅读和分析代码,可以更好地理解和掌握Java代理服务器的实现细节。在实际项目中,可以根据需求扩展Proxy...

    设计模式C++学习之代理模式(Proxy)

    代理模式是一种设计模式,它是结构型模式之一,主要用于在客户端和目标对象之间建立一个代理对象,以便控制对目标对象的访问。在C++中,代理模式可以用来为其他对象提供一种代理以控制对这个对象的访问,或者增加...

Global site tag (gtag.js) - Google Analytics