zoukankan      html  css  js  c++  java
  • Cglib invoke以及invokeSuper的一点区别

    简单记录下,解决的一个问题,Cglib的invoke和invokeSuper的区别:

      简而言之,invoke方法调用的对象没有增强过,invokeSuper方法调用的对象已经是增强了的,所以会再走一遍 MyMethodInterceptor的 interceptor方法,如果是个拦截器链条,就会重新在走一次拦截器链;

    一。准备环境 Gglib的两个jar包,因为Cglib使用了ASM生成子类;

    二。代码准备

    public class Target {
        
        public void a() {
            System.out.println(" a 方法");
        }
        
        public void b() {
            System.out.println(" b 方法");
        }
    }
    import java.lang.reflect.Method;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    public class MyMethodInterceptor implements MethodInterceptor{
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        //obj是代理后的子类 ,method是调用方法 ,args是方法入参 , proxy是MethodProxy代理对象 System.out.println(
    "myMethodInterceptor go "); Object res = proxy.invokeSuper(obj, args); return res; } }

    测试类:

    public class TestApp {
    
        public static void main(String[] args) {
            Enhancer e = new Enhancer();
            e.setSuperclass(Target.class);     
            e.setCallback(new MyMethodInterceptor());
            Target t=(Target) e.create();
            t.a();
        }
    }

    测试结果:

    myMethodInterceptor go 
     a 方法

    三。

    3.1  先解决一个问题,Target这个类里面方法写 this 就是 指的生成的Cglib子类 ,

    测试在a方法中添加一句输出this   ,结论:Cglib代理的时候target对象中的this就是Cglib子类  (你可能觉得我说的是废话,子类对象在父类的this指的不是自身吗? 你知道Spring Aop里this方法无法增强自身调用,这时候你就开始怀疑人生了)

    3.2 既然知道了this对象就是指代的自身,那我比如 this.b() 或者 b() 应该也被回调一次了 。

    public class Target {
        
        public void a() {
            System.out.println(" a 方法");
            b();
        }
        
        public void b() {
            System.out.println(" b 方法");
        }
    }

    其他类不改动代码,测试结果如下:  果然 this.b()方法也被增强了;

    myMethodInterceptor go 
     a 方法
    myMethodInterceptor go 
     b 方法

    你在 b()  打个断点,下一步就跳进入 MyMethodInterceptor 的 intercept 方法里了 ;这个似乎也没有毛病,其实原因就是 invokeSuper;invokeSuper传入的参数是Cglib代理的子类 ,就相当于 调用 Target$$EnhanceredByCGLIB这个子类的b()方法,肯定会再次进入回调;

    3.3 如何实现像AOP一样 调用自身无法增强呢?

    修改代码如下: 改动的地方已经标红了 :)

    public class Target {
        
        public void a() {
            System.out.println(" a 方法");
            b();
        }
        
        public void b() {
            System.out.println(" b 方法");
        }
    }
    
    
    public class MyMethodInterceptor implements MethodInterceptor{
        private Object target;
        
        public MyMethodInterceptor(Object target) {
            super();
            this.target = target;
        }
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("myMethodInterceptor go ");
    //      Object res = proxy.invokeSuper(obj, args);
            Object res = proxy.invoke(target, args);
            return res;
        }
    
    }
    
    public class TestApp {
    
        public static void main(String[] args) {
    //        System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\api");
            Target target = new Target();
            Enhancer e = new Enhancer();
            e.setSuperclass(Target.class);
            e.setCallback(new MyMethodInterceptor(target));
            Target t=(Target) e.create();
            t.a();
        }
    }

    测试结果如下:

    myMethodInterceptor go 
     a 方法
     b 方法

    这就和AOP的功能一毛一样了吧 ;  区别就在于 invoke 和 invokeSuper : 在我理解看来,invoke方法调用的对象没有增强过,invokeSuper方法调用的对象已经是增强了的,所以会再走一遍 MyMethodInterceptor的 interceptor方法,如果是个拦截器链条,就会重新在走一次拦截器链;

    四。

    查看下Spring CGLIB的Aop  ,  这个就是执行完 环绕通知 、 前置通知 之后执行业务方法的地方 ,target对象存的是原生的bean,没有被CGLIB代理的对象,所以就无法实现自身调用增强;

    该方法是 AopUtilsinvokeJoinpointUsingReflection 

    而与之相反的则是,@Configuration注解下类中 @Bean注解标注方法里的 方法调用,得到的是同一个@Bean对象;

    因为 BeanMethodInterceptor 的 interceptor方法  调用的invokeSuper方法 ,比如 getMan2方法调用getMan方法,那个getMan方法调用的是 CGLIB子类的getMan方法 ,此时getMan是增强后的getMan方法,这时候就会检测ThreadLocal当前线程和当前方法是否一致了,不一致尝试从容器中获取该bean对象                                      戳我查看原文

    五。查看Cglib生成子类的方案思路

    方案一。

    测试类上加上这样一句话:

    public class TestApp {
    
        public static void main(String[] args) {
            System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "E:\api");
            Target target = new Target();
            Enhancer e = new Enhancer();
            e.setSuperclass(Target.class);
            e.setCallback(new MyMethodInterceptor(target));
            Target t=(Target) e.create();
            t.a();
        }
    }

     看到控制台输出这样的:

    CGLIB debugging enabled, writing to 'E:api'
    myMethodInterceptor go 
     a 方法
     b 方法

     可以看到确实生成了CGLIB子类class文件;

     

    我的class文件通过JD-GUI查看却是有些问题  有的地方有很多label ,有知道的怎么解决的评论告诉我 多谢 :)

     public final void a()
      {
        MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
        if (tmp4_1 == null)
        {
          tmp4_1;
          CGLIB$BIND_CALLBACKS(this);
        }
        if (this.CGLIB$CALLBACK_0 != null)
          return;
        super.a();
      }

    方案二。

    我觉得是个很神奇的地方,方便以后查看  ,附上作者原文链接,无抄袭的意思  https://blog.csdn.net/lzufeng/article/details/79322391

    命令行输入

     java -classpath "D:Javajdk1.8.0_181libsa-jdi.jar" sun.jvm.hotspot.HSDB

     会弹出来一个java工具,选择 File -- > Attach to HotSpot process ,会要求输入进程号

    查看方式 新开一个命令行输入

    jps -l

      可以看到 13592 就是我们需要的;输入刚才的java小工具中,

    选择Tool --> Class Browser ,在输入框输入之前的类  Target类

    选中下面的CGLIB的子类, 选择Create .class File

     

    文件就生成成功了,找到这个class文件方式很多  ,我测试的时候是在 第一个命令行当前目录下面找到的  ; 此外还可以电脑上文件搜索那个文件名;

    (方案三。提供一种思路,可以忽略,因为我也不是很了解这个技术 ,java  探针技术 还是 agent技术 )

  • 相关阅读:
    fzuoj Problem 2177 ytaaa
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Capture the Flag
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Team Formation
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Beauty of Array
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Lunch Time
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Convert QWERTY to Dvorak
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest May Day Holiday
    zoj The 12th Zhejiang Provincial Collegiate Programming Contest Demacia of the Ancients
    zjuoj The 12th Zhejiang Provincial Collegiate Programming Contest Ace of Aces
    csuoj 1335: 高桥和低桥
  • 原文地址:https://www.cnblogs.com/lvbinbin2yujie/p/10284316.html
Copyright © 2011-2022 走看看