讲一些你所不知道的 Java 动态代理
只定义了一个方法invoke()
,参数含义如下
Object proxy
生成的代理对象Method method
调用的方法,类型为java.lang.reflect.Method
`Object[] ar
gs`调用方法的参数,array of objects
简单来说就是,调用 proxy object 上的方法,最终都会转换成对关联InvocationHandler
的invoke()
方法的调用
可以使用java.lang.reflect.Proxy
的静态方法newProxyInstance
来创建Proxy object
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
...
}
参数说明
loader 定义 proxy class 的 ClassLoader
interfaces 需要代理的接口
h 关联的 InvocationHandler
例子
==
使用动态代理打印方法的执行耗时
定义代理接口
public interface Foo {
String doSomething();
}
实现接口
public class FooImpl implements Foo {
@Override
public String doSomething() {
return "finished";
}
}
定义 InvocationHandler,target 为被代理对象的引用,在方法执行完后打印耗时
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class TimingInvocationHandler implements InvocationHandler {
private Object target;
public TimingInvocationHandler(Object target) {
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
long start = System.nanoTime();
Object result = method.invoke(target, args);
long elapsed = System.nanoTime() - start;
System.out.println(String.format("Executing %s finished in %d ns",
method.getName(),
elapsed));
return result;
}
}
测试
import org.junit.Test;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class DynamicProxyTest {
@Test
public void test() {
ClassLoader cl = DynamicProxyTest.class.getClassLoader();
Class[] interfaces = new Class[]{Foo.class};
FooImpl fooImpl = new FooImpl();
InvocationHandler timingInvocationHandler = new TimingInvocationHandler(fooImpl);
Foo foo = (Foo) Proxy.newProxyInstance(cl, interfaces, timingInvocationHandler);
foo.doSomething();
}
}
执行完会打印类似
Executing doSomething finished in 23148 ns
细节
==
生成 proxy class 的一些属性和细节
public, final, and not abstract.
类名不确定,以 $Proxy 开头
继承 java.lang.reflect.Proxy,且 Proxy 实现了 java.io.Serializable 接口,因此 proxy instance 是可以序列化的
按照 Proxy.newProxyInstance() 传入 interfaces 参数中的接口顺序来实现接口
在 proxy class 上调用 getInterfaces,getMethods,getMethod 方法,会返回实现的接口中定义的方法,顺序和创建时的参数保持一致
当调用 proxy instance 同名、同 parameter signature 方法时,invoke() 方法的 Method 参数会是最早定义这个方法的 interface 的方法,无论实际调用的方法是什么
当 Foo 为实现的代理接口之一时, proxy instanceof Foo 返 true,并且可以转换 (Foo) proxy
评论