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

Java中的动态代理

 
阅读更多

在使用CXF的时候,尤其是创建针对REST或SOAP服务的客户端时,大量的使用了动态代理。例如创建针对REST的动态代理:

RoomReservationServiceInterface service = JAXRSClientFactory.create("http://localhost:8181/room/", RoomReservationServiceInterface.class);

或针对SOAP的动态代理:

Service service = Service.create(new URL("http://localhost:8181/room/?wsdl"), new QName("http://localhost:8181/room/", "RoomReservationService"));
		RoomReservationServiceInterface port = service.getPort(RoomReservationServiceInterface.class);

另外很多mock测试框架也大量的使用它生成一堆Mock类(我没研究过,猜的,错了别怪我)

 

动态代理是Java1.3中引入的。所谓动态,是指代理类在运行时才会存在。

 

在继续之前,假设已经实现了一个动态代理,然后可以用以下代码创建一个代理实例:

 

SimpleInterface sim = (SimpleInterface) Proxy.newProxyInstance(SimpleInterface.class.getClassLoader(), new Class[]{SimpleInterface.class}, new InterfaceProxy());

看newProxyInstance()的方法签名(拷自java源码,删除了不必要的注释):

    /**
     * Returns an instance of a proxy class for the specified interfaces
     * that dispatches method invocations to the specified invocation
     * handler. 
     *
     * @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
     */
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

它需要有三个参数:

  1. classLoader:  用于加载代理类的类加载器,并且所有的interfaces参加里的类也必须对此类加载器可见
  2. interfaces: 代码类需要实现的所有的接口列表
    这里有几条需要注意:
    1.  只能是接口类,不能有具体类(包括抽象类,因为代理类会有默认的父类)
    2. 不能有重复的接口类
    3. 所有的接口需要对classLoader参数可见
    4. 如果有非public的接口,则需要在同一个包中引用它(这个应该是很显然的)
    5. 不能含有冲突的方法,如同一个方法名和参数,然后不同的返回类型等。
  3. InvocationHandler: 实现代码的关键,所有对代理类的调用都通过它的invoke()方法执行。

假设有以下两个接口:

public interface Member {

	String getName();
	int getAge();

}
public interface SimpleInterface {

	String getName();

	Member getMember();
	
	int getAge();

}

定义完接口,现在对于newProxyInstance()的所需要的三个参数,只差最后一个InvocationHandler了。要实现动态代理,就需要实现一个自定义的InvocationHandler的实现:

public class InterfaceProxy implements InvocationHandler {

	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		Class<?> returnType = method.getReturnType();
		if (returnType.isPrimitive()) {  //if int, then return 30
			return 30;
		}
		if (returnType == String.class) {  //if string, then return liugang
			return "liugang";
		}
                //else, create one more proxy for it
		return Proxy.newProxyInstance(returnType.getClassLoader(),
				new Class[] { returnType }, new InterfaceProxy());
	}
}

这里实现很简单,就是根据方法的返回类型的不同做不同的处理(看上面SimpleInterface的定义,只可能有三种类似的返回值:int, String和Member):

  1. 如果是int值,则返回一个固定的30
  2. 如果是string类型,则返回一个名字
  3. 如果是其他类型,则创建一个针对此类似的新的代码(这个类型也需要满足以上针对newProxyInstance()方法参加的要求)

有了这个代理类后,可以开始使用它们了:

		SimpleInterface sim = (SimpleInterface) Proxy.newProxyInstance(
				SimpleInterface.class.getClassLoader(),
				new Class[] { SimpleInterface.class }, new InterfaceProxy());
		
		String name = sim.getName();
		System.out.println(name);
		
		int age = sim.getAge();
		System.out.println(age);
		
		Member member = sim.getMember();
		System.out.println(member);
		System.out.println(member.getName());
		System.out.println(member.getAge());

打印的结果如下:

liugang
30
liugang
liugang
30

可以看到,即使没有显示的声明任意一个接口的实现,所以的接口对象也都拥有一个实例,并且这个实现的方法还可以调用成功。

 

为了进一步的看看这些创建出来的接口实例是个什么东西,添加一个打印类的方法:

	public static void printClass(Class<?> c) {
		//print class declaration
		System.out.print(Modifier.toString(c.getModifiers()));
		System.out.print(" ");
		System.out.print(c.getName());
		System.out.print(" ");
		//print super
		Class<?> superclass = c.getSuperclass();
		if (superclass != null) {
			System.out.print("extend ");
			System.out.print(superclass.getName());
		}
		//print interfaces
		Class<?>[] interfaces = c.getInterfaces();
		if (interfaces != null && interfaces.length > 0) {
			System.out.print("\n\t\t inplements ");
			System.out.print(interfaces[0].getName());
			for (int i = 1; i < interfaces.length; i++) {
				System.out.print(",");
				System.out.print(interfaces[0].getName());
			}
		}
		//print body
		System.out.println("{");

		//print fields
		Field[] fields = c.getDeclaredFields();
		if (fields != null && fields.length > 0) {
			for (Field f : fields) {
				printField(f);
			}
		}
		System.out.println();
		//print methods
		Method[] methods = c.getDeclaredMethods();
		if (methods != null && methods.length > 0) {
			for (Method m : methods) {
				printMethod(m);
			}
		}

		System.out.println("}");
		System.out.println();
	}

	private static void printMethod(Method m) {
		System.out.print("\t");
		System.out.print(Modifier.toString(m.getModifiers()));
		System.out.print(" ");
		System.out.print(m.getReturnType().getName());
		System.out.print(" ");
		System.out.print(m.getName());
		System.out.print("(");
		Class<?>[] parameterTypes = m.getParameterTypes();
		if (parameterTypes != null && parameterTypes.length > 0) {
			System.out.print(parameterTypes[0].getName());
			for (int i = 1; i < parameterTypes.length; i++) {
				System.out.print(",");
				System.out.print(parameterTypes[0].getName());
			}

		}
		System.out.println(");");
	}

	private static void printField(Field f) {
		System.out.print("\t");
		System.out.print(Modifier.toString(f.getModifiers()));
		System.out.print(" ");
		System.out.print(f.getType().getName());
		System.out.print(" ");
		System.out.print(f.getName());
		System.out.println(";");
	}

然后在创建的对象上应用它们:

		SimpleInterface sim = (SimpleInterface) Proxy.newProxyInstance(
				SimpleInterface.class.getClassLoader(),
				new Class[] { SimpleInterface.class }, new InterfaceProxy());

		printClass(sim.getClass());
		
		Member member = sim.getMember();
		printClass(member.getClass());

打印结果如下:

public final com.sun.proxy.$Proxy0 extend java.lang.reflect.Proxy
		 inplements com.liulutu.liugang.java.proxy.SimpleInterface{
	private static java.lang.reflect.Method m5;
	private static java.lang.reflect.Method m3;
	private static java.lang.reflect.Method m1;
	private static java.lang.reflect.Method m4;
	private static java.lang.reflect.Method m0;
	private static java.lang.reflect.Method m2;

	public final com.liulutu.liugang.java.proxy.Member getMember();
	public final int getAge();
	public final int hashCode();
	public final boolean equals(java.lang.Object);
	public final java.lang.String toString();
	public final java.lang.String getName();
}

public final com.sun.proxy.$Proxy1 extend java.lang.reflect.Proxy
		 inplements com.liulutu.liugang.java.proxy.Member{
	private static java.lang.reflect.Method m4;
	private static java.lang.reflect.Method m1;
	private static java.lang.reflect.Method m3;
	private static java.lang.reflect.Method m0;
	private static java.lang.reflect.Method m2;

	public final int getAge();
	public final int hashCode();
	public final boolean equals(java.lang.Object);
	public final java.lang.String toString();
	public final java.lang.String getName();
}

可以看到生成的类名都形如 com.sun.proxy.$Proxy* ,并且都继承了类  java.lang.reflect.Proxy ,然后实现了对应的欲代理的接口。


从上面打印出的结果可以看出,代理类中已经实现了对应的接口和方法,那么,它是怎么和上面的InvocationHandler的invoke()方法联系上的呢。具体的代码看不到,我用调试的方式,在invoke()方法上另了一个断点,然后调试以下代码:

		SimpleInterface sim = (SimpleInterface) Proxy.newProxyInstance(
				SimpleInterface.class.getClassLoader(),
				new Class[] { SimpleInterface.class }, new InterfaceProxy());
		Member member = sim.getMember();

看看调试的堆栈信息:

 

 

 

可以看到对方法的调用被转到了InvocationHandler的invoke()方法上去了。

分享到:
评论

相关推荐

    Java中动态代理的介绍及实例

    ### Java中动态代理的核心知识点详解 #### 一、动态代理概览 动态代理是Java反射机制的一个重要应用,主要用于在不修改目标对象源代码的情况下,为一个对象提供一个代理对象,这个代理对象能够控制对目标对象的...

    Java实现动态代理

    Java动态代理是Java编程中一个重要的特性,它允许我们在运行时创建代理对象,这些代理对象可以作为原有对象的“中间人”,在调用原有方法前或后执行额外的操作,如日志记录、性能监控、事务管理等。动态代理在很多...

    java中动态代理,springAop.pdf

    下面我们将详细探讨Java动态代理及其在Spring AOP中的应用。 首先,我们来看动态代理的基本概念。在Java中,动态代理主要通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口来实现。`...

    java中动态代理和反射技术.pdf

    在Java中,动态代理和反射技术是两个非常重要的概念,它们在实际开发中有着广泛的应用。动态代理允许我们在运行时创建代理类,而反射则可以让我们在运行时检查和操作类、接口、字段以及方法。 首先,代理模式是一种...

    java + 动态代理 + 动态代理实际应用场景

    1:静态代理出现的实际背景,静态代理时如何演化成动态代理 2: 动态代理demo 举例实际应用场景(载入数据库驱动的时候,使用AIDL与系统Servic进行通信) 3: 动态代理使用到基础理论:ClassLoader 加载.class字节码...

    Java反射机制和动态代理

    主要讲述Java反射机制与设计模式之一:代理模式的原理与应用;同时详细讲述了Java对代理模式的支持以及Java中动态代理的原理,应用与实践。

    java动态代理demo

    在Java动态代理中,我们首先需要定义一个或多个接口。这些接口定义了原始对象(也称为目标对象)所实现的方法。代理对象将实现这些接口,并在调用这些方法时执行额外的操作。 3. **InvocationHandler接口** `...

    java Proxy 动态代理

    在Java中,动态代理主要通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口来实现。Proxy类是用于创建一个代理对象,而InvocationHandler接口则定义了代理对象调用方法时的行为。 1. **...

    java动态代理实例

    3. **拦截器模式**:在Java动态代理中,我们可以使用`InvocationHandler`来实现拦截器。拦截器是一种设计模式,它允许我们在方法调用前后插入自定义的代码,比如事务管理、权限检查等。通过动态代理,我们可以轻松地...

    java jdk 动态代理 演示demo

    在静态代理中,我们通过编写额外的代理类来实现这一目标,但在动态代理中,代理类是在运行时生成的,无需预先编写代码。 Java JDK提供了`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口,...

    Java动态代理两种实现方式

    Java动态代理技术是Java编程中一个非常重要的特性,它允许我们在运行时动态创建具有特定行为的对象。这种技术常用于AOP(面向切面编程)和框架中,如Spring AOP,用于实现方法拦截、事务管理等功能。Java提供了两种...

    JAVA静态代理和动态代理

    Java提供了两种主要的代理实现方式:静态代理和动态代理。 **静态代理** 静态代理是程序员手动创建代理类并实现与目标对象相同的接口。代理类和目标类都必须实现相同的接口,这样代理类就可以在调用目标对象方法的...

Global site tag (gtag.js) - Google Analytics