文章目录
- 引言
- Java不支持多继承机制
- JDK 动态代理是怎么生成类的
- 那为什么CGLIB可以基于类
- 面试级总结❤️
引言
在面试中很多时候会回答到JDK动态代理的相关问题,那么我们都知道JDK动态代理是基于接口的,如果被代理类没有实现某个接口,则无法使用JDK动态代理,而只能选择CGLIB代理。那么JDK动态代理为什么得基于接口,而不能兼容基于类呢?下面我们一起来讨论一下这个问题。
Java不支持多继承机制
我们知道Java不支持多继承(不能同时继承两个类),而是能通过实现接口的方式实现多继承的这种形式。
而这就是JDK动态代理基于接口,而不能基于类的原因。
JDK 动态代理是通过Proxy.newProxyInstance()在运行期生成一个 “实现目标接口的类”,该代理类的父类始终是java.lang.reflect.Proxy,不是你的目标类。代理类不能继承目标类,它不可能同时 extends Proxy 和 extends 你自己的类。
代理类extendsProxyimplements你的接口们JDK 动态代理是怎么生成类的
ok,上面说了JDK动态代理不能基于类的根本原因,那么他是怎么根据我们自己的类生成代理类的呢?
如果你写:
UserServiceproxy=(UserService)Proxy.newProxyInstance(...);JDK 会动态生成一个代理类(可以 dump 出文件看到),类似:
publicfinalclass$Proxy0extendsProxyimplementsUserService{publicvoidcreate(){// 所有方法最终转发到 InvocationHandler.invoke(...)h.invoke(this,method,args);}}所以你能看到很重要的三点:
第一,代理类固定继承 Proxy
第二,代理类不会继承你的实现类
第三,代理类通过实现接口,所有方法都是转发到 InvocationHandler
上面就是JDK动态代理怎么生成类的大概流程
那为什么CGLIB可以基于类
因为 CGLIB 跟 JDK 动态代理完全不一样,它不是用 Proxy API,它是:
- 直接用 ASM 操作字节码
- 生成目标类的子类
- 通过重写方法进行拦截
classUserServiceImpl$$EnhancerByCGLIBextendsUserServiceImpl{@Overridepublicvoidcreate(){// 调用 MethodInterceptor}}面试级总结❤️
JDK 动态代理不能基于类的根本原因:
JDK 动态代理基于接口实现,生成的代理类固定继承自 Proxy,而 Java 不支持同时继承目标类,因此无法对类本身做代理。
CGLIB 能代理类的原因:
CGLIB 直接生成目标类的子类,通过字节码增强实现方法拦截,不依赖接口,不依赖 Proxy 的父类结构。