spring两种代理详述

AOP功能的底层,其实就是代理模式,代理模式分为两种,静态代理和动态代理

静态代理

  • 在静态代理中,代理类和委托类都必须实现同一个接口,而且代理类中必须要有委托类的一个实例。在调用代理类的接口方法时,实际会调用委托类相应的委托方法,形成代理模式。
  • 静态代理模式有两个优点:
    1. 代理类真实存在
    2. 在编译期就生成了代理类,效率高。
  • 缺点:
    1. 如果委托类过多,就会导致代理类也变多,不方便管理
    2. 如果很多委托类想要增加相同功能,那么代理类中就会出现大量相同的代码,代码冗余
    3. 在编译期就已经创建好,不灵活。

动态代理

  • 在动态代理中,不会出现大量的代理类,而是根据委托类,在运行期动态的生成代理类的模式。实现动态代理的方式有两种,JDK和Cglib。JDK是默认的代理方式,如果委托对象实现了接口,那么就会选择JDK进行代理,反之选择Cglib。
  • JDK模式动态代理: 主要需要一个Proxy类和一个InvocationHandler接口,其中的Proxy是用来生成代理类,InvocationHandler是所有的代理类都必须实现的接口。
    Proxy类是用来生成代理对象的,使用的是Proxy.newProxyInstance()方法来生成代理类。其中需要三个参数,分别是代理类的类加载器,用来创建代理对象,委托类实现的接口,代理类实例【回调接口】。在Proxy类生成代理对象时,会先生成代理对象的字节码,在生成代理对象字节码时,会先把Object类中的hashCode方法,equals方法,toString方法加进代理类字节码中,然后加入实现接口中的方法。这样代理类的字节码就生成好了。之后转换成字节流,再利用defineClass()方法生成代理类的class对象。生成的代理对象中的每一个方法都是final方法,且都用反射的方式对目标方法做了封装。
    实现了InvocationHandler的类,都会实现一个invoke()方法,这个方法会在代理类方法被调用时触发回调,他需要三个参数。代理类实例,调用的方法对象,方法需要的参数。在invoke方法中,会触发目标方法的调用【method.invoke(委托对象,参数)】。在目标方法调用的前后,都可以加一些逻辑,这也就是AOP的底层原理。
  • Cglib模式动态代理:当委托类没有实现接口时,会选择用Cglib进行动态代理。底层是在字节码的层面上,继承委托类,覆盖其中的方法完成代理。所以遇到final类或者方法就无法实现代理。
    用Cglib实现动态代理,有一个重要的类Enhancer(字节码增强器)和一个接口MethodInteceptor。enhancer类就是用来创建代理对象的,因为Cglib是在字节码层面上生成代理对象,所以要通过enhancer.setSuperClass(parentClass)来设置父类的字节码,并且通过setCallBack(MethodInteceptor)设置代理对象【回调接口】。通过enhancer的create()方法创建代理对象。
    所有的代理类都必须实现MethodInteceptor这个接口,并且实现inteceptor()方法,inteceptor方法会在在代理类的代理方法触发回调,在inteceptor()方法中会触发委托方法的调用,通过proxy.invokeSuper(obj, arg)调用目标方法,在目标方法调用的前后,也都可以增加逻辑代码。这也就是AOP的另外一个底层原理。

而AOP,就是对动态代理模式的再次封装,我认为AOP对动态代理的封装分为两部分:
第一部分,对代理对象生成的封装。其中JDK的Proxy.newInstance()和Cglib的Enhancer.create()分别被封装到了JDKDynamicAopProxy类和Cglib2AopProxy类中,它们也都分别实现了InvocationHandler接口和MethodInteceptor接口。而这两个类又进行了一次统一的封装,被封装到了ProxyFactoryBean的getObject()方法中。在通过Cglib生成代理对象时,使用了Spring容器的另一个重要功能——IoC,委托类的字节码通过IoC容器获得。
第二部分是对织入的封装。AOP中织入的功能,是通过一条拦截器链实现,其中的拦截器就是Advisor——通知器,而Advisor由两部分组成,Pointcut——切入点和Advice——通知。每次调用动态代理方法时,都会遍历拦截器链,通过matches()对advisor进行判断,将能应用到委托方法上的advisor,通过AdvisorAdaptor,将advisor中的advice转换成对应类型的inteceptor——拦截器,其中有before,after,throws等几种类型,放到inteceptors——拦截器列表并返回。通过proceed()方法继续向下调用,直至拦截器尾,最后调用目标方法,完成代理方法的调用。其中的通知器也是通过IoC容器获取到的。

©️2020 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页