Java的类
反射机制中包括了动态代理技术,其核心设计围绕InvocationHandler
接口和Proxy类。下面给出一个
例子:
public interface Car {
public void description();
}
我们定义一个Car接口,然后实现它:
public class BigCar implements Car {
public void description() {
System.out.println("BigCar");
}
}
一般情况下,我们可以这样使用它:
Car car = new BigCar();
car.description();
程序会输出:
BigCar
如果我们要用Proxy来做,首先需要一个实现了InvocationHandler的代理类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class CarProxy implements InvocationHandler {
private Object delegate;
public Object newInstance(Object delegate) {
this.delegate = delegate;
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),
delegate.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return method.invoke(delegate, args);
}
}
使用方法如下:
CarProxy cp = new CarProxy();
Car car = (Car) cp.newInstance(BigCar.class.newInstance());
car.description();
执行程序,同样会输出BigCar。但代码似乎复杂了很多,这样做有什么
意义呢?在我接触过的
开源项目中,使用Proxy一般目的有两个:一是为了在程序逻辑执行时插入其它逻辑(比如添加日志或是改写参数传递);二是为了改变程序逻辑。
首先从第一种情况说起。注意到InvocationHandler里面的invoke方法,整个Proxy机制的核心就是invoke方法。invoke方法接收Method,即接口方法,我们在这个层面就可以插入一些额外的逻辑,比如添加日志:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class CarProxy implements InvocationHandler {
private Object delegate;
public Object newInstance(Object delegate) {
this.delegate = delegate;
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),
delegate.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) {
System.out.println("before method: " + method.getName());
Object returnObj = null;
try {
returnObj = method.invoke(delegate, args);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} finally {
System.out.println("after method: " + method.getName());
}
return returnObj;
}
}
此时再执行:
CarProxy cp = new CarProxy();
Car car = (Car) cp.newInstance(BigCar.class.newInstance());
car.description();
程序输出如下:
before method: description
BigCar
after method: description
下面我们看看第二种情况,即改
写代码逻辑:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class CarProxy implements InvocationHandler {
private Object delegate;
public Object newInstance(Object delegate) {
this.delegate = delegate;
return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),
delegate.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) {
if (method.getName().equals("description")) {
System.out.println("Caught by proxy.");
}
return null;
}
}
此时执行:
CarProxy cp = new CarProxy();
Car car = (Car) cp.newInstance(BigCar.class.newInstance());
car.description();
程序输出如下:
Caught by proxy.
可见car.description的逻辑已经被Proxy拦到并改写了。这些用法在框架级代码中都很普遍,比如RESTEasy的ClientProxy[1]。
此外,我们在CarProxy中通过:
private Object delegate;
保留了它代理的实现类BigCar。
实际上这不是必须的,而Proxy框架提供给我们的是更灵活的设计,实际上一个代理可以代理多个类。
下面给出个例子,首先定义两个不同的接口及其实现类:
public interface Flavor {
public void taste();
}
public class Spicy implements Flavor {
public void taste() {
System.out.println("Spicy");
}
}
public interface Color {
public void show();
}
public class Red implements Color {
public void show() {
System.out.println("Red");
}
}
然后我们用一个InvocationHandler同时代理两个接口[2]:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MultipleProxy implements InvocationHandler {
private Class[] interfaces;
private Object[] delegates;
public MultipleProxy(Class[] interfaces, Object[] delegates) {
this.interfaces = (Class[]) interfaces.clone();
this.delegates = (Object[]) delegates.clone();
}
public Object invoke(Object proxy, Method m, Object[] args)
throws Throwable {
Class declaringClass = m.getDeclaringClass();
for (int i = 0; i < interfaces.length; i++) {
if (declaringClass.isAssignableFrom(interfaces[i])) {
try {
return m.invoke(delegates[i], args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}
return methodNotFound(proxy, m, args);
}
protected Object methodNotFound(Object proxy, Method m,
Object[] args)
throws Throwable {
throw new InternalError("unexpected method dispatched: " + m);
}
}
使用这个代理:
Class[] proxyInterfaces = new Class[]{Color.class, Flavor.class};
Object obj = Proxy.newProxyInstance(Color.class.getClassLoader(),
proxyInterfaces,
new MultipleProxy(proxyInterfaces, new Object[]{new Red(), new Spicy()}));
Color color = (Color) obj;
color.show();
Flavor flavor = (Flavor) obj;
flavor.taste();
程序输出如下:
Red
Spicy
[1] http://grepcode.com/file/repository.jboss.org/maven2/org.jboss.resteasy/resteasy-jaxrs/1.1-RC2/org/jboss/resteasy/client/core/ClientProxy.java
[2] 代码参考自:http://docs.oracle.com/javase/1.3/docs/guide/reflection/proxy.html