在使用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()方法上去了。