这两天好好研究了动态代理,把一些体会写出来,以备后用
代理分为静态代理和动态代理
静态代理需要手动为每个代理类的每个方法添加要实现的功能(如日志)
而动态代理则为需要添加功能的类自动生成代理类,其实jdk proxy已经为我们提供了方法
静态代理就是面向对象中的代理模式,使用面向对象的方式实现代理对象,这个代理对象的类是自己手工编写的。
动态代理是编程语言根据代理规则自动生成代理类,并产生代理对象。常用的动态代理有 JDK Proxy 和 cglib。
JDK Proxy 是在运行时产生代理类的字节码,再由类加载器加载这些字节码然后创建代理对象。
Cglib 是使用一种叫做 ASM 的字节码工具,由程序的方式产生字节码。
迷惑的地方时invoke方法是何时被执行的
我们在InvocationHandler实现类中写一个newInstance(),用来产生代理类,返回一个object类型的 new Proxy.newProxyInstance(loader, interfaces, h)的代理类
里面有三个参数,第一个是用来将目标对象(即真实类)加载到JVM上,第二个是实现目标对象接口的所有方法,有意思的是第三个方法,当我们调用目标对象的方法时,就会转到第三个参数,它指的是代理类对象,讲调用第三个方法时,它会自动调用invoke方法
在invoke(Object proxy, Method method, Object[] args)方法中,
Object proxy -----代理类对象
Method method -----被代理对象的方法(这里不是接口的抽象方法了,是具体的实现类中的方法)
Object[] args -----该方法的参数数组
在方法里面可以加入需要添加的如日志,安全性检查功能
方法里面需要实现的就一句,method.invoke(target,args);
即目标对象,参数,它的作用就是执行目标对象里面的方法
参考了下面的讲解
1. Proxy即动态代理类;
2. Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用;
它有三个参数:
ClassLoader loader ----指定被代理对象的类加载器
Class[] Interfaces ----指定被代理对象所以事项的接口
InvocationHandler h ----指定需要调用的InvocationHandler对象
3. 实现InVocationHandler接口的LogHandler_old对象
这个对象的invoke()方法就是Proxy这个动态代理类所代理的接口类的抽象方法的真实实现;
它有三个参数:
Object proxy -----代理类对象
Method method -----被代理对象的方法(这里不是接口的抽象方法了,是具体的实现类中的方法)
Object[] args -----该方法的参数数组
JDK中具体的动态代理类是怎么产生的呢?
1.产生代理类$Proxy0类
执行了Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
将产生$Proxy0类,它继承Proxy对象,并根据第二个参数,实现了被代理类的所有接口,自然就可以生成接口要实现的所有方法了(这时候会重写hashcode,toString和equals三个方法),但是还没有具体的实现体;
2. 将代理类$Proxy0类加载到JVM中
这时候是根据Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第一个参数----就是被代理类的类加载器,把当前的代理类加载到JVM中
3. 创建代理类$Proxy0类的对象
调用的$Proxy0类的$Proxy0(InvocationHandler)构造函数,生成$Proxy0类的对象
参数就是Proxy.newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)它的第三个参数
这个参数就是我们自己实现的InvocationHandler对象,我们知道InvocationHandler对象中组合加入了代理类代理的接口类的实现类;所以,$Proxy0对象调用所有要实现的接口的方法,都会调用InvocationHandler对象的invoke()方法实现;
4. 生成代理类的class byte
动态代理生成的都是二进制class字节码
-----------------------------自己的理解,不足之处,恳请指点---------------------------------------------------