服务器之家:专注于VPS、云服务器配置技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - Java教程 - 详解Alibaba Java诊断工具Arthas查看Dubbo动态代理类

详解Alibaba Java诊断工具Arthas查看Dubbo动态代理类

2022-11-09 11:44朱季谦 Java教程

这篇文章主要介绍了Alibaba Java诊断工具Arthas查看Dubbo动态代理类 ,它可以帮助我们查看JDK或者javassist生成的动态代理类,当然,它的功能远不止此,还可以在生产环境进行诊断,需要的朋友可以参考下

阅读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/

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

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

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

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

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

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

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

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

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

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

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

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

详解Alibaba Java诊断工具Arthas查看Dubbo动态代理类

首先,启动提供者方法——

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类详情——

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;

}

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

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,随便放到一个目录当中,例如——

详解Alibaba Java诊断工具Arthas查看Dubbo动态代理类

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

详解Alibaba Java诊断工具Arthas查看Dubbo动态代理类

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

详解Alibaba Java诊断工具Arthas查看Dubbo动态代理类

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

详解Alibaba Java诊断工具Arthas查看Dubbo动态代理类

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

详解Alibaba Java诊断工具Arthas查看Dubbo动态代理类

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

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

控制台就会打印出该动态代理类的内部结构——

/*
* 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")去调用远程接口时,其实是调用了动态代理生成的方法——

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

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

到此这篇关于Alibaba Java诊断工具Arthas查看Dubbo动态代理类的文章就介绍到这了,更多相关Alibaba Java诊断工具Arthas内容请搜索服务器之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持服务器之家!

原文链接:https://www.cnblogs.com/zhujiqian/p/16114954.html

延伸 · 阅读

精彩推荐
  • Java教程Java基础概述面试题复习

    Java基础概述面试题复习

    这篇文章主要介绍了java基础面试题,文中的描述非常详细,对正在学习java基础的小伙伴们有非常好的帮助,需要的朋友可以参考下,希望能给你带来帮助...

    manor的大数据奋斗之路7622021-11-16
  • Java教程Java数组越界问题实例解析

    Java数组越界问题实例解析

    这篇文章主要介绍了Java数组越界问题实例解析,具有一定参考价值,需要的朋友可以了解下。...

    inione10622021-01-28
  • Java教程Java多线程 ThreadLocal原理解析

    Java多线程 ThreadLocal原理解析

    这篇文章主要介绍了Java多线程 ThreadLocal原理,ThreadLoal 变量,线程局部变量,同一个 ThreadLocal 所包含的对象,在不同的 Thread 中有不同的副本,下面文章也...

    冬日毛毛雨11712022-03-05
  • Java教程深入理解SpringCloud之Eureka注册过程分析

    深入理解SpringCloud之Eureka注册过程分析

    eureka是一种去中心化的服务治理应用,其显著特点是既可以作为服务端又可以作为服务向自己配置的地址进行注册,这篇文章主要介绍了深入理解SpringClo...

    洛阳融科聂晨9052021-05-06
  • Java教程java8 统计字符串字母个数的几种方法总结(推荐)

    java8 统计字符串字母个数的几种方法总结(推荐)

    下面小编就为大家分享一篇java8 统计字符串字母个数的几种方法总结(推荐),具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来吧...

    尚云峰1119862021-02-22
  • Java教程Java基于Swing实现的打猎射击游戏代码

    Java基于Swing实现的打猎射击游戏代码

    这篇文章主要介绍了Java基于Swing实现的打猎射击游戏代码,包含完整的游戏事件处理与逻辑流程控制,具有不错的参考借鉴价值,需要的朋友可以参考下 ...

    shichen20145012019-12-04
  • Java教程客户端设置超时时间真的很重要

    客户端设置超时时间真的很重要

    今天小编就为大家分享一篇关于客户端设置超时时间真的很重要,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小...

    Sam哥哥8152021-06-19
  • Java教程Java AbstractMethodError案例分析详解

    Java AbstractMethodError案例分析详解

    这篇文章主要介绍了Java AbstractMethodError案例分析详解,本篇文章通过简要的案例,讲解了该项技术的了解与使用,以下就是详细内容,需要的朋友可以参考下...

    liunim904412021-11-30