JDK动态代理可以不基于接口吗?( 三 )


其实如果不看上面的分析,我们也应该知道,要扩展一个类有常见的两种方式,继承父类或实现接口 。这两种方式都允许我们对方法的逻辑进行增强,但现在不是由我们自己来重写方法,而是要想办法让jvm去调用InvocationHandler中的invoke方法,也就是说代理类需要和两个东西关联在一起:

  • 被代理类
  • InvocationHandler
而jdk处理这个问题的方式是选择继承父类Proxy,并把InvocationHandler存在父类的对象中:
public class Proxy implements java.io.Serializable {protected InvocationHandler h;protected Proxy(InvocationHandler h) {Objects.requireNonNull(h);this.h = h;}//...}通过父类Proxy的构造方法,保存了创建代理对象过程中传进来的InvocationHandler的实例,使用protected修饰保证了它可以在子类中被访问和使用 。但是同时,因为java是单继承的,因此在继承了Proxy后,只能通过实现目标接口的方式来实现方法的扩展,达到我们增强目标方法逻辑的目的 。
扯点别的其实看完源码、弄明白代理对象生成的流程后,我们还可以用另一种方法实现动态代理:
public static void main(String[] args) throws Exception {Class<?> proxyClass = Proxy.getProxyClass(Test3.class.getClassLoader(), Worker.class);Constructor<?> constructor = proxyClass.getConstructor(InvocationHandler.class);InvocationHandler workHandler = new WorkHandler(new Programmer());Worker worker = (Worker) constructor.newInstance(workHandler);worker.work();}运行结果与之前相同,这种写法其实就是抽出了我们前面介绍的几个核心方法,中间省略了一些参数的校验过程,这种方式可以帮助大家熟悉jdk动态代理原理,但是在使用过程中还是建议大家使用标准方式,相对更加安全规范 。
总结本文从源码以及实验的角度,分析了jdk动态代理生成代理对象的流程,通过代理类的实现原理分析了为什么jdk动态代理一定要基于接口实现 。总的来说,jdk动态代理的应用还是非常广泛的,例如在Spring、Mybatis以及Feign等很多框架中动态代理都被大量的使用,可以说学好jdk动态代理,对于我们阅读这些框架的底层源码还是很有帮助的 。
以上文章来源于码农参上 ,作者Dr Hydra

【JDK动态代理可以不基于接口吗?】


推荐阅读