动态代理机制
Java 里面,动态代理是通过 Proxy.newProxyInstance()方法来实现的,它需要传入被动态代理的接口类
// 生成代理文件写入磁盘
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
ITradinPostService runService = (ITradinPostService) Proxy.newProxyInstance(ITradinPostService.class.getClassLoader(), new Class[]{ITradinPostService.class}, (proxy, method, args1) -> {
System.out.println("动态代理");
return "hello";
});
System.out.println(runService.run());
JDK 动态代理的底层实现
之所以要传入接口,不能传入类,还是取决于 JDK 动态代理的底层实现
JDK 动态代理会在程序运行期间动态生成一个代理类$Proxy0。
这个动态生成的代理类
会继承 java.lang.reflect.Proxy 类,同时还会实现被代理类的接口 IHelloService。
在 Java 中,是不支持多重继承的。而每个动态代理类都会继承 Proxy 类(这也是 JDK
动态代理的实现规范),所以就导致 JDK 里面的动态代理只能代理接口,而不能代理
实现
public final class $Proxy0 extends Proxy implements ITradinPostService {
// 省略
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final String run() throws {
try {
return (String)super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
// 省略
}
Proxy 这个类只是保存了动态代理的处理器InvocationHandler,如果不抽出来,直接设置到$Proxy0 动态代理类里面,也是可以的。
- 动态代理本身的使用场景或者需求,只是对原始实现的一个拦截,然后去做一些功能的增强或者扩展。而实际的开发模式也都是基于面向接口来开发,所以基于接口来实现动态代理,从需求和场景都是吻合的。当然确实可能存在有些类没有实现接口的,那这个时候,JDK 动态代理确实无法满足。
- 在 Java 里面,类的继承关系的设计,更多的是考虑到共性能力的抽象,从而提高 代码的重用性和扩展性,而动态代理也是在做这样一个事情,它封装了动态代理类生成的抽象逻辑、判断一个类是否是动态代理类、InvocationHandler 的持有等等,那么把这些抽象的公共逻辑放在 Proxy 这个父类里面,很显然是一个比较正常的设计思路。