美文网首页
arthas助力阅读dubbo源码

arthas助力阅读dubbo源码

作者: 王兴岭 | 来源:发表于2020-09-10 15:00 被阅读0次

    框架

    Dubbo 2.7.7
    arthas-boot 3.4.0
    系统: Mac

    1. Linux/Unix/Mac 安装arthas

    curl -O https://arthas.aliyun.com/arthas-boot.jar
    java -jar arthas-boot.jar
    

    SPI是dubbo实现动态修改服务参数的基石,比如下面代码

        RegistryFactory REGISTER_FACTORY = ExtensionLoader.getExtensionLoader(RegistryFactory.class)
            .getAdaptiveExtension();
        Registry registry = REGISTER_FACTORY
            .getRegistry(URL.valueOf("zookeeper://127.0.0.1:2181?client=curator"));
    

    返回的REGISTER_FACTORYorg.apache.dubbo.registry.RegistryFactory$Adaptive@19bb07ed,
    但是这个以$Adaptive为结尾的RegistryFactory到底是什么鬼,整个项目查找都没有这个class文件,如果对Dubbo的SPI源码了解的话应该就知道RegistryFactory$Adaptive是动态拼接的字符串,然后使用字节码技术编译成class,并通过自定的ClassLoader加载到java虚拟机内存中的,所以dubbo框架源码中是找不到这个class的.但是这个class的内容我很好奇到底是什么?

    方法1:使用arthas(本文的重点)(包含完整的步骤),以AdapteExtendsionTestDemo为例(要使用debug模式启动main方法,不然arthas连接AdapteExtendsionTest进程失败)

    public class AdapteExtendsionTest {
        RegistryFactory REGISTER_FACTORY = ExtensionLoader.getExtensionLoader(RegistryFactory.class)
            .getAdaptiveExtension();
        Registry registry = REGISTER_FACTORY
            .getRegistry(URL.valueOf("zookeeper://127.0.0.1:2181?client=curator"));
        System.in.read();
      }
    }
    

    最后要有System.in.read(),获取其他方法,让main线程保活,不然没办法使用arthas,通过断点发现REGISTER_FACTORY.toString()返回的是org.apache.dubbo.registry.RegistryFactory$Adaptive@19bb07ed,把@19bb07ed去掉就是RegistryFactory$Adaptive完整的类路径org.apache.dubbo.registry.RegistryFactory$Adaptive.
    打开终端启动arthas-boot服务

     java -jar arthas-boot.jar
    

    执行结果如下

    [INFO] arthas-boot version: 3.4.0
    [INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
    * [1]: 24835 
      [2]: 30548 org.jetbrains.jps.cmdline.Launcher
      [3]: 30549 com.leimo.demo.AdapteExtendsionTest
      [4]: 25244 org.jetbrains.idea.maven.server.RemoteMavenServer36
      [5]: 508 org.apache.zookeeper.server.quorum.QuorumPeerMain
    

    通过上面的列表可以找到AdapteExtendsionTest,就是我们刚刚跑的测试类名
    [3]: 30549 com.leimo.demo.AdapteExtendsionTest
    编号是[3],在控制台输入3

    3
    [INFO] arthas home: /Users/lemo-wu/.arthas/lib/3.4.0/arthas
    [INFO] Try to attach process 31331
    [INFO] Attach process 31331 success.
    [INFO] arthas-client connect 127.0.0.1 3658
      ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.                           
     /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'                          
    |  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.                          
    |  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |                         
    `--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'                          
                                                                                    
    
    wiki      https://arthas.aliyun.com/doc                                         
    tutorials https://arthas.aliyun.com/doc/arthas-tutorials.html                   
    version   3.4.0                                                                 
    pid       31331                                                                 
    time      2020-09-10 14:49:41                                                   
    
    [arthas@31331]$ 
    
    

    如果显示[arthas@xxxx]$就表示连接成功了
    然后在arhhas终端输入

    [arthas@31331]$ jad org.apache.dubbo.registry.RegistryFactory$Adaptive
    

    控制台就会将class反编译的结果打印在控制台上了

    [arthas@31331]$ jad org.apache.dubbo.registry.RegistryFactory$Adaptive
    
    ClassLoader:                                                                                                                                                                                                             
    +-sun.misc.Launcher$AppClassLoader@18b4aac2                                                                                                                                                                              
      +-sun.misc.Launcher$ExtClassLoader@56ac3a89                                                                                                                                                                            
    
    Location:                                                                                                                                                                                                                
    /Users/lemo-wu/.m2/repository/org/apache/dubbo/dubbo/2.7.7/dubbo-2.7.7.jar                                                                                                                                               
    
    /*
     * Decompiled with CFR.
     */
    package org.apache.dubbo.registry;
    
    import org.apache.dubbo.common.URL;
    import org.apache.dubbo.common.extension.ExtensionLoader;
    import org.apache.dubbo.registry.Registry;
    import org.apache.dubbo.registry.RegistryFactory;
    
    public class RegistryFactory$Adaptive
    implements RegistryFactory {
        @Override
        public Registry getRegistry(URL uRL) {
            String string;
            if (uRL == null) {
                throw new IllegalArgumentException("url == null");
            }
            URL uRL2 = uRL;
            String string2 = string = uRL2.getProtocol() == null ? "dubbo" : uRL2.getProtocol();
            if (string == null) {
                throw new IllegalStateException(new StringBuffer().append("Failed to get extension (org.apache.dubbo.registry.RegistryFactory) name from url (").append(uRL2.toString()).append(") use keys([protocol])").toString());
            }
            RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getExtension(string);
            return registryFactory.getRegistry(uRL);
        }
    }
    
    Affect(row-cnt:1) cost in 563 ms.
    

    jad是arthas的命令集之一,作用就是用来将class反编译成java输出.如果想将反编译的内容输出到一个文件中,可以使用 > 输入文件路径,比如

    [arthas@31331]$ jad org.apache.dubbo.registry.RegistryFactory$Adaptive > /opt/abc.java
    

    验证输出结果

    # cd /opt
    # ls
    # cat abc.java
    

    控制台输出结果如下

    ClassLoader:
    +-sun.misc.Launcher$AppClassLoader@18b4aac2
      +-sun.misc.Launcher$ExtClassLoader@56ac3a89
    
    Location:
    /Users/lemo-wu/.m2/repository/org/apache/dubbo/dubbo/2.7.7/dubbo-2.7.7.jar
    
    /*
     * Decompiled with CFR.
     */
    package org.apache.dubbo.registry;
    
    import org.apache.dubbo.common.URL;
    import org.apache.dubbo.common.extension.ExtensionLoader;
    import org.apache.dubbo.registry.Registry;
    import org.apache.dubbo.registry.RegistryFactory;
    
    public class RegistryFactory$Adaptive
    implements RegistryFactory {
        @Override
        public Registry getRegistry(URL uRL) {
            String string;
            if (uRL == null) {
                throw new IllegalArgumentException("url == null");
            }
            URL uRL2 = uRL;
            String string2 = string = uRL2.getProtocol() == null ? "dubbo" : uRL2.getProtocol();
            if (string == null) {
                throw new IllegalStateException(new StringBuffer().append("Failed to get extension (org.apache.dubbo.registry.RegistryFactory) name from url (").append(uRL2.toString()).append(") use keys([protocol])").toString());
            }
            RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getExtension(string);
            return registryFactory.getRegistry(uRL);
        }
    }
    
    Affect(row-cnt:1) cost in 202 ms.
    

    方法2. 找到到生成java字符串的方法

    org.apache.dubbo.common.extension.ExtensionLoader类的createAdaptiveExtensionClass方法

      private Class<?> createAdaptiveExtensionClass() {
            String code = new AdaptiveClassCodeGenerator(type, cachedDefaultName).generate();
            ClassLoader classLoader = findClassLoader();
            org.apache.dubbo.common.compiler.Compiler compiler = ExtensionLoader.getExtensionLoader(org.apache.dubbo.common.compiler.Compiler.class).getAdaptiveExtension();
            return compiler.compile(code, classLoader);
        }
    

    通过IDE在ClassLoader classLoader = findClassLoader();断点,然后watch code,将code的内容粘贴到一个文本编辑区中查看

    package org.apache.dubbo.registry;
    
    import org.apache.dubbo.common.URL;
    import org.apache.dubbo.common.extension.ExtensionLoader;
    import org.apache.dubbo.registry.Registry;
    import org.apache.dubbo.registry.RegistryFactory;
    
    public class RegistryFactory$Adaptive
    implements RegistryFactory {
        @Override
        public Registry getRegistry(URL uRL) {
            String string;
            if (uRL == null) {
                throw new IllegalArgumentException("url == null");
            }
            URL uRL2 = uRL;
            String string2 = string = uRL2.getProtocol() == null ? "dubbo" : uRL2.getProtocol();
            if (string == null) {
                throw new IllegalStateException(new StringBuffer().append("Failed to get extension (org.apache.dubbo.registry.RegistryFactory) name from url (").append(uRL2.toString()).append(") use keys([protocol])").toString());
            }
            RegistryFactory registryFactory = ExtensionLoader.getExtensionLoader(RegistryFactory.class).getExtension(string);
            return registryFactory.getRegistry(uRL);
        }
    }
    
    

    参考资料:
    https://arthas.aliyun.com/doc/en/quick-start.html

    相关文章

      网友评论

          本文标题:arthas助力阅读dubbo源码

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