在使用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)
它需要有三个参数:
- classLoader: 用于加载代理类的类加载器,并且所有的interfaces参加里的类也必须对此类加载器可见
- interfaces: 代码类需要实现的所有的接口列表
这里有几条需要注意:
1. 只能是接口类,不能有具体类(包括抽象类,因为代理类会有默认的父类)
2. 不能有重复的接口类
3. 所有的接口需要对classLoader参数可见
4. 如果有非public的接口,则需要在同一个包中引用它(这个应该是很显然的)
5. 不能含有冲突的方法,如同一个方法名和参数,然后不同的返回类型等。 - 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):
- 如果是int值,则返回一个固定的30
- 如果是string类型,则返回一个名字
- 如果是其他类型,则创建一个针对此类似的新的代码(这个类型也需要满足以上针对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()方法上去了。
相关推荐
Word格式的Java中动态代理的介绍及实例,有详细注释。
java中动态代理,springAop.pdf
java中动态代理和反射技术.pdf
这几个文件是我当时自己总结的,这几天突然翻出来了,上传上来给需要的同学们看看,说不定有人需要呢
1:静态代理出现的实际背景,静态代理时如何演化成动态代理 2: 动态代理demo 举例实际应用场景(载入数据库驱动的时候,使用AIDL与系统Servic进行通信) 3: 动态代理使用到基础理论:ClassLoader 加载.class字节码...
主要讲述Java反射机制与设计模式之一:代理模式的原理与应用;同时详细讲述了Java对代理模式的支持以及Java中动态代理的原理,应用与实践。
java动态代理 完整版 java动态代理 完整版 java动态代理 完整版 java动态代理 完整版 java动态代理 完整版
java jdk 动态代理 演示demo
java动态代理实例 要想理解拦截器的知识 最好要先理解java动态代理这块
JAVA静态代理和动态代理
Java实现动态代理的两种方式。 相对来说cglib更加方便。可以实现为实现接口的类(非final类)
Java 动态代理详解(学习资料);Java 动态代理详解(学习资料);Java 动态代理详解(学习资料);Java 动态代理详解(学习资料);Java 动态代理详解(学习资料);
自己总结的代理模式和Java中的动态代理模式,有源码
讲述JAVA的动态代理的原理,以及通过JAVA的动态代理来实现AOP。简洁,易懂,学习AOP的入门级文档
适用于初探java动态代理模式,精简易懂。
这个是个人做的JAVA实现动态代理的笔记