`
liugang594
  • 浏览: 977458 次
  • 性别: 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()方法上去了。

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics