嗯,这个问题的核心本质,是 JDK 动态代理本身的机制来决定的。 首先,在 Java 里面,动态代理是通过 Proxy.newProxyInstance()方法来实现的,它需 要传入被动态代理的接口类。
之所以要传入接口,不能传入类,还是取决于 JDK 动态代理的底层实现(如图)。
JDK 动态代理会在程序运行期间动态生成一个代理类$Proxy0,这个动态生成的代理类
会继承 java.lang.reflect.Proxy 类,同时还会实现被代理类的接口 IHelloService。
在 Java 中,是不支持多重继承的。而每个动态代理类都会继承 Proxy 类(这也是 JDK
动态代理的实现规范),所以就导致 JDK 里面的动态代理只能代理接口,而不能代理
实现类。
我分析过动态代理的源码,发现 Proxy 这个类只是保存了动态代理的处理器
InvocationHandler,如果不抽出来,直接设置到$Proxy0 动态代理类里面,也是可以
的。
如果这么做,就可以针对实现类来做动态代理了。作者为什么这么设计,我认为有几个
方面的原因。
1. 动态代理本身的使用场景或者需求,只是对原始实现的一个拦截,然后去做一些功
能的增强或者扩展。而实际的开发模式也都是基于面向接口来开发,所以基于接口
来实现动态代理,从需求和场景都是吻合的。当然确实可能存在有些类没有实现接
口的,那这个时候,JDK 动态代理确实无法满足。
2. 在 Java 里面,类的继承关系的设计,更多的是考虑到共性能力的抽象,从而提高
代码的重用性和扩展性,而动态代理也是在做这样一个事情,它封装了动态代理类
生成的抽象逻辑、判断一个类是否是动态代理类、
InvocationHandler 的持有等等,
那么把这些抽象的公共逻辑放在 Proxy 这个父类里面,很显然是一个比较正常的设
计思路。
总的来说,我认为这个设计上并没有什么特别值得讨论的地方,因为我认为技术方案的
设计是解决特定场景问题的。
如果一定要针对普通类来做动态代理,可以选择 cglib 这个组件,它会动态生成一个被
代理类的子类,子类重写了父类中所有非 final 修饰的方法,在子类中拦截父类的所有
方法调用从而实现动态代理。