什么是动态代理
静态代理和动态代理是实现代理模式的两种方式。
静态代理是在编译时就已经确定了代理类和被代理类的关系,代理类需要实现和被代理类相同的接口,并在代理类中手动编写被代理类的相关逻辑。这种方式的缺点是如果接口方法较多,或者被代理类经常发生变化,那么代理类需要频繁地进行修改,不利于维护。
动态代理则是在运行时动态生成代理类,不需要手动编写代理类的代码。在Java中,动态代理是通过反射机制实现的,通过Proxy类和InvocationHandler接口来动态生成代理对象。这种方式的优点是更加灵活,可以在运行时根据需要动态地生成代理类,而且只需要编写一次通用的代理逻辑即可。
总的来说,静态代理的代理关系在编译时就已经确定,而动态代理的代理关系在运行时动态生成,动态代理更加灵活但可能有更高的性能开销。
demo
1 | import java.lang.reflect.InvocationHandler; |
在invoke里面可以定义动态代理的代码逻辑,主体还是利用反射进行调用
定义一个接口和一个简单的实现类
1 | public interface Student { |
1 | public class Boy implements Student{ |
使用Proxy.newProxyInstance生成动态代理对象,并进行调用测试
1 | Boy xiaoMing = new Boy(); |
原理
proxyClassFile就是最后生成动态代理的class字节码,我们可以dump下来
构造函数直接调用Proxy的
var1是我们传入的handle
相当于把Proxy里面的这个变量赋值成我们的handle
有一些静态代码块,后面解释
发现这个动态类里面有我们的study函数,里面直接调用了handle的invoke,刚好就进入到我们自己写的invoke代码里了,这里的m3就是刚才我们静态代码反射获取的method,刚好用上了
同时还有一些自带的方法
换一个定义
getMethod修改了
方法的定义与调用也修改了
源码分析
ProxyGenerator.generateClassFile是生成字节码的核心部分
一上来先add这三个方法,所以可以看到我们的proxy动态类里面默认会有这三个代理实现的方法
遍历我们给的interface接口,然后获取Methods并加入到ProxyMethod里
接下来再加一个默认的构造函数,并且把之前的proxyMethods也放入到methods里面,同时还把每一个proxyMethods都对应一个field字段(m1,m2这些),同时最后还会生成一个静态代码块
构造函数就是调用了Proxy(父类)的构造函数,传入了一个handle
静态代码块就是利用getMethod给我们的field字段赋值
上面的部分相当于是基础的信息处理,后面就是一些具体写成字节码的逻辑了,这里就不过多分析了
总结
其实动态代理和静态代理也比较类似
静态代理需要我们自己实现和被代理类相同的接口
而动态代理相当于jdk帮我们做了这些工作,他把需要代理的接口方法写到动态代理对象里面去了
最终这两种代理模式生成的类对象结构都类似,都重写了需要代理的接口方法
只是说静态代理把方法实现逻辑写在了代理对象里
而动态代理把实现逻辑写在了InvocationHandler的invoke里