• [编织消息框架][JAVA核心技术]cglib动态代理


    先在mavne项目里添加cglib库

    maven仓库搜索cglib版本

    maven地址:http://mvnrepository.com/

    点击最新的版本 3.2.5

    复制到pom.xml  dependencies 标签下

    <dependency>
        <groupId>cglib</groupId>
        <artifactId>cglib</artifactId>
        <version>3.2.5</version>
    </dependency>

    接着在TestProxy.class添加方法

    public static void testCglib() {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(UserServiceImpl.class);
        enhancer.setCallback(new MethodInterceptor() {
    
            @Override
            public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            return proxy.invokeSuper(obj, args);
    
            }
        });
        UserService impTarget = (UserService) enhancer.create();
        run("cglib",impTarget);
    }
    public static void main(String[] args) {
        testNative();
        testJdk();
        testCglib();
    }

    继续运行测试:

    native: 177 native: 191 native: 132 native: 179 native: 132 native: 152 native: 183 native: 131 native: 133 native: 132 native: 131 native: 133 native: 132 native: 132 native: 133
    jdk: 218 jdk: 172 jdk: 172 jdk: 173 jdk: 172 jdk: 172 jdk: 172 jdk: 172 jdk: 173 jdk: 172 jdk: 174 jdk: 172 jdk: 172 jdk: 172 jdk: 173
    cglib: 294 cglib: 271 cglib: 271 cglib: 284 cglib: 270 cglib: 270 cglib: 268 cglib: 268 cglib: 269 cglib: 268 cglib: 269 cglib: 269 cglib: 280 cglib: 268 cglib: 273

    可以看出 cglib比jdk还要慢

    我们来查看下生成的class指令有多少条

    先加一行System.in.read();  防止程序退出

    public static void main(String[] args) throws IOException {
        testNative();
        testJdk();
        testCglib();
        System.in.read();  
    }

    运行HSDB工具

    1)、打开cmd窗口,运行命令:java -classpath "%JAVA_HOME%/lib/sa-jdi.jar" sun.jvm.hotspot.HSDB

    2)、点击file菜单下第一项


    弹出

    3)、打开任务管理器,在任务管理器菜单查看->选择列->勾选PID

    找到当前运行java程序的进程号pid,输入到上图的文本框中,点击ok弹出

    4)、点击工具(tools)菜单下的第一项Class Browser。弹出

    5)、输入包名TestProxy回车.只要看cglib生成的动态类

    只要看 super class 实现类

    6)、点击Create .class File,在HSDB工具运行目录下下生产cglib动态代理类

    用jd-gui打开

    逻辑跟JDK差不多,只要不同部分 

      public final String getName(int paramInt)
      {
        MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
        if (tmp4_1 == null)
        {
          tmp4_1;
          CGLIB$BIND_CALLBACKS(this);
        }
        MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
        if (tmp17_14 != null) {
          return (String)tmp17_14.intercept(this, CGLIB$getName$0$Method, new Object[] { new Integer(paramInt) }, CGLIB$getName$0$Proxy);
        }
        return super.getName(paramInt);
      }

    CGLIB$CALLBACK_0 是cglib MethodInterceptor 对象

    由于jd-gui无法完全反编译 看不到CGLIB$getName$0$Proxy  MethodProxy 对象是如何生成的

    我们用javap 看下 getName 生成多少条指令大概知道为什么会慢

    javap -v TestProxy$UserServiceImpl$$EnhancerByCGLIB$$aa69a57.class > d.txt

      public final java.lang.String getName(int);
        descriptor: (I)Ljava/lang/String;
        flags: ACC_PUBLIC, ACC_FINAL
        Code:
          stack=9, locals=2, args_size=2
             0: aload_0
             1: getfield      #40                 // Field CGLIB$CALLBACK_0:Lnet/sf/cglib/proxy/MethodInterceptor;
             4: dup
             5: ifnonnull     17
             8: pop
             9: aload_0
            10: invokestatic  #44                 // Method CGLIB$BIND_CALLBACKS:(Ljava/lang/Object;)V
            13: aload_0
            14: getfield      #40                 // Field CGLIB$CALLBACK_0:Lnet/sf/cglib/proxy/MethodInterceptor;
            17: dup
            18: ifnull        53
            21: aload_0
            22: getstatic     #46                 // Field CGLIB$getName$0$Method:Ljava/lang/reflect/Method;
            25: iconst_1
            26: anewarray     #48                 // class java/lang/Object
            29: dup
            30: iconst_0
            31: iload_1
            32: new           #50                 // class java/lang/Integer
            35: dup_x1
            36: swap
            37: invokespecial #53                 // Method java/lang/Integer."<init>":(I)V
            40: aastore
            41: getstatic     #55                 // Field CGLIB$getName$0$Proxy:Lnet/sf/cglib/proxy/MethodProxy;
            44: invokeinterface #61,  5           // InterfaceMethod net/sf/cglib/proxy/MethodInterceptor.intercept:(Ljava/lang/Object;Ljava/lang/reflect/Method;[Ljava/lang/Object;Lnet/sf/cglib/proxy/MethodProxy;)Ljava/lang/Object;
            49: checkcast     #63                 // class java/lang/String
            52: areturn
            53: aload_0
            54: iload_1
            55: invokespecial #38                 // Method com/eyu/onequeue/TestProxy$UserServiceImpl.getName:(I)Ljava/lang/String;
            58: areturn

    从数量上看比jdk生成的指令差不多有二倍多,慢是必然的,但cglib比jdk1.6快,原因是jdk1.6生成差不多有上百代指令

    顺便说下spring 代理有两种模式 1.cglib 2.jdk

    proxyTargetClass 属性,设置为true,则使用CGLIB代理,此属性默认为false,使用JDK动态代理

    <aop:scoped-proxy proxy-target-class="true" /> 
  • 相关阅读:
    USACO第三道题
    uva350 PseudoRandom Numbers
    uva10879 Code Refactoring
    Scrum 冲刺第一篇 晨曦
    WC.exe 晨曦
    [LeetCode 126] 单词梯II(Word Ladder II)
    [LeetCode 129] 根节点到叶子节点数字求和(Sum Root to Leaf Numbers)
    [LeetCode 125] 验证回文(Valid Palindrome)
    [LeetCode 123] 买入与卖出股票的最佳时机III(Best Time to Buy and Sell Stock III)
    [LeetCode 124] 二叉树最大路径和(Binary Tree Maximum Path Sum)
  • 原文地址:https://www.cnblogs.com/solq111/p/6633215.html
Copyright © 2020-2023  润新知