美文网首页
spring 动态代理

spring 动态代理

作者: shoyu666 | 来源:发表于2022-04-11 10:46 被阅读0次

    Spring的aop(面向切面编程)是通过代理实现,Spring的代理分为2种。

    • JDK dynamic proxies(JDK)
    • CGLIB

    JDK

    默认情况下,当一个类实现了接口,Spring 就会使用JDK代理,但是只代理接口的方法。如果一个对象有其它非接口方法,非接口方法是不会被代理的。

    CGLIB

    CGLIB底层:使用字节码处理框架ASM,来转换字节码并生成新的类。
    CGLIB代理会创建2个对象,一个是被代理对象,一个是实现了advice(增强逻辑,或切面逻辑)的sub class。所以CGLIB不能代理final修饰的class。

    容易混淆的代理语义

    public class SimplePojo implements Pojo {
       public void foo() {
          // this next method invocation is a direct call on the 'this' reference
          this.bar();
       }
          public void bar() {
          // some logic...
       }
    }
    
    foo方法直接调用
    image.png
    public class Main {
       public static void main(String[] args) {
             Pojo pojo = new SimplePojo();
                // this is a direct method call on the 'pojo' reference
          pojo.foo();
       }
    }
    
    foo方法代理调用
    image.png
    public class Main {
       public static void main(String[] args) {
             ProxyFactory factory = new ProxyFactory(new SimplePojo());
          factory.addInterface(Pojo.class);
          factory.addAdvice(new RetryAdvice());
          Pojo pojo = (Pojo) factory.getProxy();
                // this is a method call on the proxy!
          pojo.foo();
       }
    }
    

    foo方法是被代理的,但是foo方法调用bar方法时用的是this,所以bar方法不会被代理。

    bar方法的代理调用
    public class SimplePojo implements Pojo {
       public void foo() {
          // this works, but... gah!
          ((Pojo) AopContext.currentProxy()).bar();
       }
          public void bar() {
          // some logic...
       }
    }
    

    ((Pojo) AopContext.currentProxy()).bar(); 是先获取代理对象,再调用bar方法。
    ps:这里只是为了方便阐述代理才使用 ((Pojo) AopContext.currentProxy());
    ((Pojo) AopContext.currentProxy()); 会是代码跟spring 强耦合,不建议这样使用。

    bar方法的代理调用方案思考

    目前主要有几种方式

    • 将foo方法和bar方法独立成2个对象。
    • 将SimplePojo 对象再注入到 SimplePojo
    SimplePojo {
       SimplePojo  self;
    }
    

    判断是否被代理,区分是JDK代理还是CGLIB代理

    //org.springframework.aop.support.AopUtils
    AopUtils.isAopProxy
    AopUtils.isJdkDynamicProxy
    AopUtils.isCglibProxy
    

    AspectJ

    AspectJ 没有上面的 self-invocation 问题,因为AspectJ不是一个proxy的aop框架。
    Aspectj原理:通过asm操作Java字节码的方式。

    参考:

    https://docs.spring.io/spring-framework/docs/3.0.0.M3/reference/html/ch08s06.html

    相关文章

      网友评论

          本文标题:spring 动态代理

          本文链接:https://www.haomeiwen.com/subject/oddisrtx.html