写点什么

讲一些你所不知道的 Java 动态代理

  • 2021 年 11 月 12 日
  • 本文字数:1328 字

    阅读完需:约 4 分钟

只定义了一个方法invoke(),参数含义如下


  • Object proxy生成的代理对象

  • Method method调用的方法,类型为 java.lang.reflect.Method

  • `Object[] ar


【一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义】
浏览器打开:qq.cn.hn/FTf 免费领取
复制代码


gs`调用方法的参数,array of objects


简单来说就是,调用 proxy object 上的方法,最终都会转换成对关联InvocationHandlerinvoke()方法的调用


可以使用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

评论

发布
暂无评论
讲一些你所不知道的Java动态代理