详解Alibaba Java诊断工具Arthas查看Dubbo * 类

作者:朱季谦 时间:2021-08-04 03:16:28 

阅读Dubbo源码过程中,会发现,Dubbo消费端在做远程调用时,默认通过 Javassist 框架为服务接口生成 * 类,调用javassist框架下的JavassistProxyFactory类的getProxy(Invoker invoker, Class<?>[] interfaces)方法,动态生成一个存放在JVM中的 * 类。

public <T> T getProxy(Invoker<T> invoker, Class<?>[] interfaces) {
   return (T) Proxy.getProxy(interfaces).newInstance(new InvokerInvocationHandler(invoker));
}

那么,问题来了,如果我们想要一睹该动态生成的代理类内部结构是怎样的,如何才能便捷做到的?

这就是我想介绍的一款工具,它可以帮助我们查看JDK或者javassist生成的 * 类,当然,它的功能远不止此,还可以在生产环境进行诊断。

Arthas 是Alibaba开源的Java诊断工具,官方在线文档地址:https://arthas.aliyun.com/doc/

根据官网上的介绍,它还可以解决以下问题&mdash;&mdash;&mdash;&mdash;

当你遇到以下类似问题而束手无策时,Arthas可以帮助你解决:

这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?

我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?

遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?

线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!

是否有一个全局视角来查看系统的运行状况?

有什么办法可以监控到JVM的实时运行状态?

怎么快速定位应用的热点,生成火焰图?

怎样直接从JVM内查找某个类的实例?

这些方案本文暂不展开,这里只展开通过该工具查看Dubbo生成的 * 类。

我是直接在使用dubbo-parent源码中的例子,分别启动了提供者与消费者。

详解Alibaba Java诊断工具Arthas查看Dubbo * 类

首先,启动提供者方法&mdash;&mdash;

public class Application {
   public static void main(String[] args) throws Exception {
           startWithBootstrap();  
   }
   private static boolean isClassic(String[] args) {
       return args.length > 0 && "classic".equalsIgnoreCase(args[0]);
   }
   private static void startWithBootstrap() {
       ServiceConfig<DemoServiceImpl> service = new ServiceConfig<>();
       service.setInterface(DemoService.class);
       service.setRef(new DemoServiceImpl());
       DubboBootstrap bootstrap = DubboBootstrap.getInstance();
       RegistryConfig registryConfig = new RegistryConfig("zookeeper://127.0.0.1:2181");
       registryConfig.setTimeout(20000);
       ProtocolConfig protocolConfig = new ProtocolConfig();
       protocolConfig.setName("dubbo");
       protocolConfig.setHost("192.168.100.1");
       protocolConfig.setPort(20877);
       bootstrap.application(new ApplicationConfig("dubbo-demo-api-provider"))
               .registry(registryConfig)
               .service(service)
               .protocol(protocolConfig)
               .start()
               .await();
   }
}

注意,需要配置RegistryConfig自己的zookeeper, protocolConfig.setHost("xxx.xxx.xxx.xxx")设置成你本地内网的ip即可;

DemoServiceImpl类详情&mdash;&mdash;

public class DemoServiceImpl implements DemoService {
   private static final Logger logger = LoggerFactory.getLogger(DemoServiceImpl.class);

@Override
   public String sayHello(String name) {
       logger.info("Hello " + name + ", request from consumer: " + RpcContext.getContext().getRemoteAddress());
       return "Hello " + name + ", response from provider: " + RpcContext.getContext().getLocalAddress();
   }

public CompletableFuture<String> sayHelloAsync(String name) {
       return null;

}

接着,启动消费者,这里可以设置一个休眠时间,这样就可以一直维持消费者运行在内存当中&mdash;&mdash;

public class Application {
   public static void main(String[] args) {
           runWithRefer();
   }
   private static void runWithRefer() {
       RegistryConfig registryConfig = new RegistryConfig("zookeeper://127.0.0.1:2181");
       registryConfig.setTimeout(30000);
       ProtocolConfig protocolConfig = new ProtocolConfig();
       protocolConfig.setName("dubbo");
       protocolConfig.setHost("192.168.200.1");
       protocolConfig.setPort(20899);
       ReferenceConfig<DemoService> reference = new ReferenceConfig<>();
       reference.setApplication(new ApplicationConfig("dubbo-demo-api-consumer"));
       reference.setRegistry(registryConfig);
       reference.setInterface(DemoService.class);
       DemoService service = reference.get();
       String message = service.sayHello("dubbo");
       System.out.println("打印了5555555"+message);
       try {
           Thread.sleep(100000000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
}

当Dubbo的服务提供者与消费者都正常运行时,说明此时JVM虚拟机内存里已经存在动态生成的代理类,这时,我们就可以开始通过arthas-boot.jar工具进行查看了。

首先,将arthas-boot.jar工具下载到你本地,我的是Windows,随便放到一个目录当中,例如&mdash;&mdash;

详解Alibaba Java诊断工具Arthas查看Dubbo * 类

接着,直接在运行着Dubbo消费端进程的IDEA上打开Terminal&mdash;&mdash;

详解Alibaba Java诊断工具Arthas查看Dubbo * 类

然后,输入 java -jar C:\Users\92493\Downloads\12229238_g\arthas-boot.jar ,arthas正常运行成功话,将列出当前JVM上运行的进程&mdash;&mdash;

详解Alibaba Java诊断工具Arthas查看Dubbo * 类

可以看到我们刚刚启动的provider进程与consumer进程,这时,只需要输入对应进程前面的编号【5】,就可以将Arthas 关联到启动类为 org.apache.dubbo.demo.consumer.Application的 Java 进程上了&mdash;&mdash;

详解Alibaba Java诊断工具Arthas查看Dubbo * 类

到这一步,我们就可以通过指令 sc *.proxy *模糊查询带有proxy标志的类名了, * 生成的类一般都是以Proxy标志&mdash;&mdash;

详解Alibaba Java诊断工具Arthas查看Dubbo * 类

其中,这里的org.apache.dubbo.common.bytecode.proxy0就是消费者生成的 * 类,我们可以直接反编译去查看它内部结构&mdash;&mdash;

[arthas@57676]$ jad org.apache.dubbo.common.bytecode.proxy0

控制台就会打印出该 * 类的内部结构&mdash;&mdash;

/*
* Decompiled with CFR.
*
* Could not load the following classes:
* com.alibaba.dubbo.rpc.service.EchoService
* org.apache.dubbo.common.bytecode.ClassGenerator$DC
* org.apache.dubbo.demo.DemoService
* org.apache.dubbo.rpc.service.Destroyable
  */
  package org.apache.dubbo.common.bytecode;
import com.alibaba.dubbo.rpc.service.EchoService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.concurrent.CompletableFuture;
import org.apache.dubbo.common.bytecode.ClassGenerator;
import org.apache.dubbo.demo.DemoService;
import org.apache.dubbo.rpc.service.Destroyable;
public class proxy0 implements ClassGenerator.DC,Destroyable,EchoService,DemoService {
public static Method[] methods;
private InvocationHandler handler;
public String sayHello(String string) {
   Object[] objectArray = new Object[]{string};
   Object object = this.handler.invoke(this, methods[0], objectArray);
   return (String)object;
}
public CompletableFuture sayHelloAsync(String string) {
   Object[] objectArray = new Object[]{string};
   Object object = this.handler.invoke(this, methods[1], objectArray);
   return (CompletableFuture)object;
}
public Object $echo(Object object) {
   Object[] objectArray = new Object[]{object};
   Object object2 = this.handler.invoke(this, methods[2], objectArray);
   return object2;
}
public void $destroy() {
   Object[] objectArray = new Object[]{};
   Object object = this.handler.invoke(this, methods[3], objectArray);
}
public proxy0() {
}
public proxy0(InvocationHandler invocationHandler) {
   this.handler = invocationHandler;
 }
}

在Dubbo案例当中,当我们执行 String message = service.sayHello("dubbo")去调用远程接口时,其实是调用了 * 生成的方法&mdash;&mdash;

public String sayHello(String string) {
   Object[] objectArray = new Object[]{string};
   Object object = this.handler.invoke(this, methods[0], objectArray);
   return (String)object;
}

举一反三,这个Arthas工具类可以在线上生产环境查看一些我们新部署的代码,看是否是新改动的。

来源:https://www.cnblogs.com/zhujiqian/p/16114954.html

标签:Alibaba,Java,诊断工具,Arthas
0
投稿

猜你喜欢

  • ArrayList的自动扩充机制实例解析

    2021-10-20 17:38:29
  • Activiti流程图查看实例

    2022-09-10 17:51:44
  • Android RecyclerView实现水平、垂直方向分割线

    2023-07-24 15:40:35
  • SSH框架网上商城项目第24战之Struts2中处理多个Model请求的方法

    2023-02-14 20:49:21
  • Java实战在线选课系统的实现流程

    2022-12-19 10:34:30
  • C#多线程中的异常处理操作示例

    2023-07-16 06:10:10
  • 关于idea中Java Web项目的访问路径问题

    2023-01-04 21:23:32
  • SpringBoot超详细讲解@Value注解

    2022-03-06 12:05:36
  • springboot大文件上传、分片上传、断点续传、秒传的实现

    2023-06-16 02:18:30
  • 举例讲解Java中Piped管道输入输出流的线程通信控制

    2021-06-25 14:19:58
  • SpringBoot 创建容器的实现

    2022-04-03 08:41:02
  • SpringBoot项目多数据源及mybatis 驼峰失效的问题解决方法

    2023-07-25 07:09:08
  • Android 实现自定义圆形listview功能的实例代码

    2022-06-20 06:58:29
  • Android图像处理之霓虹滤镜效果

    2023-08-11 14:37:41
  • 被kafka-client和springkafka版本坑到自闭及解决

    2023-08-23 15:07:36
  • 浅谈redis key值内存消耗以及性能影响

    2022-11-09 20:35:17
  • java9迁移注意问题总结

    2022-07-19 11:26:30
  • JAVA SPI特性及简单应用代码实例

    2021-11-11 14:54:54
  • Android仿微信键盘切换效果

    2022-05-01 08:06:41
  • C#使用for循环移除HTML标记

    2022-02-02 08:35:23
  • asp之家 软件编程 m.aspxhome.com