框架
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_FACTORY
是org.apache.dubbo.registry.RegistryFactory$Adaptive@19bb07ed
,
但是这个以$Adaptive
为结尾的RegistryFactory
到底是什么鬼,整个项目查找都没有这个class文件,如果对Dubbo
的SPI源码了解的话应该就知道RegistryFactory$Adaptive
是动态拼接的字符串,然后使用字节码技术编译成class,并通过自定的ClassLoader
加载到java虚拟机内存中的,所以dubbo框架源码中是找不到这个class的.但是这个class的内容我很好奇到底是什么?
方法1:使用arthas(本文的重点
)(包含完整的步骤),以AdapteExtendsionTest
Demo为例(要使用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);
}
}
网友评论