# 动态代理实现原理
要想知道 AOP 的实现原理,首先要把动态代理给搞清楚,动态代理又分为 JDK 动态代理和 CGLIB 代理,下面,就来讲一下这两种动态代理
# JDK 动态代理
JDK 动态代理,顾名思义是 JDK 提供的一项功能,它的实现方式是 运行时织入 ,性能有一定损失,但是不需要特殊的编译器与类加载器
JDK 动态代理需要一个被代理的接口与实现接口的类,之后新建一个代理对象并实现 InvocationHandler 接口,通过 Proxy.newProxyInstance () 方法来获取代理对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| public interface Dog { void eat(); void sleep(); void run(); }
public class Labrador implements Dog { @Override public void eat() { System.out.println("Labrador eat!"); }
@Override public void sleep() { System.out.println("Labrador sleep!"); }
@Override public final run() { System.out.println("Labrador run!"); } }
public class DogProxy implements InvocationHandler { private Object target;
public DogProxy(Object target) { super(); this.target = target; }
public Object createProxy() { ClassLoader classLoader = target.getClass().getClassLoader(); Class<?>[] interfaceClass = target.getClass().getInterfaces(); Object newProxyInstance = Proxy.newProxyInstance(classLoader, interfaceClass, this); return newProxyInstance; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("进入代理"); Object object = method.invoke(target, args); System.out.println("退出代理"); return object; } }
public class Main { public static void main(String[] args) { Dog dog = new Labrador(); DogProxy proxy = new DogProxy(dog); Dog newDog = (Dog)proxy.createProxy(); newDog.eat(); newDog.sleep(); newDog.run(); } }
|
最终的结果为 :
![20220604165154]()
那么这一切是怎么实现的呢,为什么 JDK 动态代理一定需要一个接口呢,为什么实体类就不能使用 JDK 动态代理呢
我们在刚刚的 Main 函数中加一行代码 :
1 2 3 4 5 6 7 8
| public static void main(String[] args) { System.out.println("代理类继承了 : " + newDog.getClass().getSuperclass().getName()); System.out.print("代理类实现了 " ); for (Class<?> anInterface : newDog.getClass().getInterfaces()) { System.out.println(anInterface.getName()); } }
|
通过上面的代码我们就可以看出来这个代理类实现了那些方法
![20220604162635]()
可以看到,newDog 这个代理类实现了我们自己写的 Dog 接口,并且继承了 reflect.Proxy 这个类
所以我们看到,JDK 动态代理之所以只能代理接口,是因为在生成代理对象的过程中,这个代理对象会继承 reflect.Proxy 这个类,java 是单继承,一个类只能继承单个类,所以 JDK 动态代理不能代理类,只能通过获取这个类所实现的接口,然后使动态类实现这些接口,在 invoke 方法里面调用方法的时候,可以看到是使用了反射的方式,调用了被代理类中的方法,final 修饰的方法也可以被直接调用,因为动态类实现了对应的接口而不是继承
接口中所有的方法都为 public, 非 public 的方法不会出现在接口中,所以 JDK 代理无法代理非 public 方法
我去看了一下源码,现在我们来梳理一下创建 JDK 动态代理的过程
- 首先新建一个 Dog 实体类和 DogProxy 类对象
- 通过 Proxy.newProxyInstance (ClassLoader, InterFaces, InvocationHandler) 方法来创建代理类,此时生成了一个代理类和一个 Proxy 类实例,并且这个动态代理类继承 Proxy 类
- 调用方法时,其内部 (即动态代理类内部), 调用其父类的 InvocationHandler 的 invoke 方法,也就是说,在进行第二步时,其中有一个参数便是 InvocationHandler, 其实方法内部将这个 InvocationHandler 赋给了 Proxy 实例,此时便调用了这个 InvocationHandler 中的 invoke 方法
- 在方法内部,是我们所定义的代码,而 Method 则是原对象 Dog 实例中对应方法的反射
从上文可以更好的理解为什么只能代理 public 方法,在第 2 步中,获取了被代理对象实现的所有的接口,才可以在创建动态代理类的时候实现对应的方法,也才能反射为 Method 被 InvocationHandler 使用
# CGLIB 动态代理
CGLIB 动态大力和 JDK 动态代理不同,CGLIB 是根据被代理对象生成子类,并在子类的基础上覆盖父类方法得到动态代理类
我们来看创建 CGLIB 代理的不同的代码 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| public class DogProxyCgLib implements MethodInterceptor { private Object target;
public DogProxyCgLib(Object target) { super(); this.target = target; }
@Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("进入代理"); Object object = methodProxy.invokeSuper(o, objects); System.out.println("退出代理"); return object; }
public Object createProxy() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } }
|
运行结果如下 :
![20220604170942]()
可以看到,eat 和 sleep 方法都进行了代理,但是 run 方法并没有,因为 run 方法是 final 的,而 CGLIB 是通过子类实现动态代理的,子类是无法继承 final 方法的
详细讲讲 CGLIB 动态代理的流程
- 创建
Dog 和 DogProxyCgLib 实例 - 调用
DogProxyCgLib 内部 createProxy 方法来新建动态代理类- 新建一个字节码增强器
- 设置父类
- 设置回调函数,也就是
DogProxyCgLib 本身 - 调用 create 方法创建动态代理类
- 调用方法
- 如果该方法是 final, 直接跳转到被代理对象的方法
- 如果该方法为 public 且不为 final, 则调用动态代理的相应方法,该方法会跳转到 MethodInterceptor 中的 intercept 方法,以此实现增强效果
方法在被调用的时候,首先会进行判断,如果是 final 或非 public 方法,直接调用配代理对象的对应方法,其他情况的话,进入动态代理对象的对应方法
![20220605011948]()
随后被转发到 intercept 方法,进行增强
而在 intercept 方法中,有四个参数 :
Object o : 动态代理类Method method : 被代理的类的方法Object[] objects : 方法的参数MethodProxy methodProxy : 可以当作是这个方法 (包含被代理和代理) 的集合
这几个参数都是在代理对象中生成的
- 第一个参数不用说,在代理对象中直接
this 搞定 - 第二个参数是事先利用 ReflectUtils.findMethods 方法 (原理为反射) 得到的
- 第三个参数则是传递进来的参数
- 第四个参数则是通过 MethodProxy 的 create 这个静态方法来生成的,里面包含了代理方法和被代理方法的映射关系
![20220605013242]()
ok 回归 intercept 方法,如果我们选择使用第二个参数来调用原始方法,即
1
| method.invoke(target, objects);
|
原理来说就是通过反射,这也是最简单的一种,但是这种方法没有体现 CGLIB 的特点,即 FastClass
如果选择第四个参数来调用方法,则又分出两种方法 :
使用 invoke 方法
当我们使用 methodProxy.invoke (target, objects) 来调用方法时,进入方法,是通过被代理对象的 fastClass 来调用方法
使用 invokeSuper 方法
当我们使用 methodProxy.invokeSuper (o, objects) 来调用方法时,进入方法,是通过代理对象的 fastClass 来调用方法,也就是上面图片上的 CGLIB$sleep$0 () 这个方法,而这个方法体就是调用父类的 sleep 方法,也就是调用被代理对象的对应方法
可能有点绕,再梳理一下 :
以下是 invoke 方式实现代理的时序图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| sequenceDiagram autonumber Main->Dog : Dog() Dog-->Main : new Dog Main->DogProxyCgLib : DogProxyCgLib() DogProxyCgLib-->Main : new DogProxyCgLib Main->DogProxyCgLib : createProxy(Dog) DogProxyCgLib-->Main : cgDog Main->cgDog : public方法 cgDog->DogProxyCgLib : intercept方法 DogProxyCgLib->MethodProxy : invoke方法 MethodProxy->FastClass : invoke方法 FastClass-> Dog : public方法 Dog-->FastClass : Object 返回值 FastClass-->MethodProxy : Object 返回值 MethodProxy-->DogProxyCgLib : Object 返回值 DogProxyCgLib-->cgDog : Object 返回值 cgDog-->Main : Object 返回值
|
以下是 invokeSuper 方式实现代理的时序图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| sequenceDiagram autonumber Main->Dog : Dog() Dog-->Main : new Dog Main->DogProxyCgLib : DogProxyCgLib() DogProxyCgLib-->Main : new DogProxyCgLib Main->DogProxyCgLib : createProxy(Dog) DogProxyCgLib-->Main : cgDog Main->cgDog : public方法 cgDog->DogProxyCgLib : intercept方法 DogProxyCgLib->MethodProxy : invokeSuper方法 MethodProxy->代理对象的FastClass : invoke方法 代理对象的FastClass-> cgDog : public方法 cgDog->Dog : public方法 Dog-->cgDog : Object 返回值 cgDog-->代理对象的FastClass : Object 返回值 代理对象的FastClass-->MethodProxy : Object 返回值 MethodProxy-->DogProxyCgLib : Object 返回值 DogProxyCgLib-->cgDog : Object 返回值 cgDog-->Main : Object 返回值
|
以下是利用反射 (即第二个参数) 实现动态代理的时序图
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| sequenceDiagram autonumber Main->Dog : Dog() Dog-->Main : new Dog Main->DogProxyCgLib : DogProxyCgLib() DogProxyCgLib-->Main : new DogProxyCgLib Main->DogProxyCgLib : createProxy(Dog) DogProxyCgLib-->Main : cgDog Main->cgDog : public方法 cgDog->DogProxyCgLib : intercept方法 DogProxyCgLib->Dog : 反射调用public方法 Dog-->DogProxyCgLib : Object 返回值 DogProxyCgLib-->cgDog : Object 返回值 cgDog-->Main : Object 返回值
|
这样一来应该就很清楚了
至此,AOP 的实现原理算是讲的差不多了,花了我整整一天去查资料和研究原理,弄懂了之后其实感觉挺简单的