在使用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()方法上去了。
相关推荐
### Java中动态代理的核心知识点详解 #### 一、动态代理概览 动态代理是Java反射机制的一个重要应用,主要用于在不修改目标对象源代码的情况下,为一个对象提供一个代理对象,这个代理对象能够控制对目标对象的...
Java动态代理是Java编程中一个重要的特性,它允许我们在运行时创建代理对象,这些代理对象可以作为原有对象的“中间人”,在调用原有方法前或后执行额外的操作,如日志记录、性能监控、事务管理等。动态代理在很多...
下面我们将详细探讨Java动态代理及其在Spring AOP中的应用。 首先,我们来看动态代理的基本概念。在Java中,动态代理主要通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口来实现。`...
在Java中,动态代理和反射技术是两个非常重要的概念,它们在实际开发中有着广泛的应用。动态代理允许我们在运行时创建代理类,而反射则可以让我们在运行时检查和操作类、接口、字段以及方法。 首先,代理模式是一种...
1:静态代理出现的实际背景,静态代理时如何演化成动态代理 2: 动态代理demo 举例实际应用场景(载入数据库驱动的时候,使用AIDL与系统Servic进行通信) 3: 动态代理使用到基础理论:ClassLoader 加载.class字节码...
主要讲述Java反射机制与设计模式之一:代理模式的原理与应用;同时详细讲述了Java对代理模式的支持以及Java中动态代理的原理,应用与实践。
在Java动态代理中,我们首先需要定义一个或多个接口。这些接口定义了原始对象(也称为目标对象)所实现的方法。代理对象将实现这些接口,并在调用这些方法时执行额外的操作。 3. **InvocationHandler接口** `...
在Java中,动态代理主要通过`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口来实现。Proxy类是用于创建一个代理对象,而InvocationHandler接口则定义了代理对象调用方法时的行为。 1. **...
3. **拦截器模式**:在Java动态代理中,我们可以使用`InvocationHandler`来实现拦截器。拦截器是一种设计模式,它允许我们在方法调用前后插入自定义的代码,比如事务管理、权限检查等。通过动态代理,我们可以轻松地...
在静态代理中,我们通过编写额外的代理类来实现这一目标,但在动态代理中,代理类是在运行时生成的,无需预先编写代码。 Java JDK提供了`java.lang.reflect.Proxy`类和`java.lang.reflect.InvocationHandler`接口,...
Java动态代理技术是Java编程中一个非常重要的特性,它允许我们在运行时动态创建具有特定行为的对象。这种技术常用于AOP(面向切面编程)和框架中,如Spring AOP,用于实现方法拦截、事务管理等功能。Java提供了两种...
Java提供了两种主要的代理实现方式:静态代理和动态代理。 **静态代理** 静态代理是程序员手动创建代理类并实现与目标对象相同的接口。代理类和目标类都必须实现相同的接口,这样代理类就可以在调用目标对象方法的...