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

目录

阅读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源码中的例子,分别启动了提供者与消费者。

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

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

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

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

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

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

其中,这里的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内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • java JSON解析库Alibaba Fastjson用法详解

    本文实例讲述了java JSON解析库Alibaba Fastjson用法.分享给大家供大家参考,具体如下: Json是一种轻量级的数据交换格式,应该在一个程序员的开发生涯中是常接触的.简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言. 易于人阅读和编写,同时也易于机器解析和生成,并有效地提升网络传输效率. 现在主流的对象与 JSON 互转的工具很多,这里介绍的是阿里巴巴的开源库 - Fastjson.Fastjson是一个Java库,可用于将Java对象转换为其JSON表示.它还可用

  • Java中利用Alibaba开源技术EasyExcel来操作Excel表的示例代码

    一.读Excel 1.Excel表格示例 2.对象示例 @Data public class DemoData { private String string; private Date date; private Double doubleData; } 3.监听器(重点部分) // 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去 public class DemoDataListener e

  • Java之SpringCloudAlibaba Sentinel组件案例讲解

    Sentinel 是什么 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.Sentinel 以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度保护服务的稳定性. 官网:https://github.com/alibaba/Sentinel 中文官网:https://github.com/alibaba/Sentinel/wiki Sentinel与Hystrix的区别 由于Hystrix不再积极的开发,进入维护阶段,现在越来越多的开发者在项目中使用Spring Cloud Al

  • IntelliJ IDEA安装插件阿里巴巴Java开发手册(Alibaba Java Coding Guidelines)

    以前看到过个:Java开发手册(阿里巴巴-公开版),这是个pdf文档,里面描述了一些Java开发的规约,里面确实有很多好用的规约,要是在学校就有机会看看的话,那么,在毕业之后,实际工作中就会少很多坑.现在,阿里巴巴又一次对这个文档进行了升级,直接变成了一个插件.你需要的就是:知道有这么个插件,然后,还得安装这个插件,那么以后,你在写代码的时候,这个插件就会自动的纠正你在写代码的时候的一些很low的不规范代码. 下面看怎么在这个 IntelliJ IDEA 上安装这个插件. 通过Jetbrains

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

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

  • SpringBoot整合java诊断工具Arthas解读

    目录 一.Arthas官方文档 二.springBoot整合方式 1.pom文件引入 2.yaml文件引入 3.下载arthas-tunnel-server 4.启动Arthas Tunnel Server及spring项目 5.登录Arthas Tunnel Server 6.输入命令进行测试 总结 一.Arthas官方文档 https://arthas.aliyun.com/doc/ 二.springBoot整合方式 1.pom文件引入 <dependency> <groupId&g

  • Java开源诊断工具Arthas使用方法详解

    一.前言 1.热更新代码的场景 (1)当线上服务器出现问题时,有些时候现有的手段不足以发现问题所在,可能需要追加打印日志或者增加一些调试代码,如果我们去改代码重新部署,会破坏问题现场,可以通过热部署的手段来增加调试代码 (2)线上出现紧急bug,通过Review代码找到问题,修改好后打包部署的流程可能比较久,可以通过热部署代码及时解决问题 二.使用阿里巴巴开源的Java诊断工具 ---Arthas,他可以附着在我们的Java服务器进程上面,查看服务器状态,jvm状态等各种参数指标,还可以进行热更

  • Java基础详解之集合框架工具Collections

    一.Collections 说明:Collcetions是集合框架中的工具,特点是方法都是静态的. 二.Collections中的常见方法 1,对list进行二分查找:前提该集合一定要有序. int binarySearch(list,key);//要求list集合中的元素都是Comparable的子类. int binarySearch(list,key,Comparator); 2,对list集合进行排序. sort(list); sort(list,comaprator); 3,对集合取最

  • 详解记录Java Log的几种方式

    在Java中记录日志的方式有如下几种: 一.System.out.println(最简单) 1.输出到控制台:System.out.println("XXX"); 2.输出到指定文件: import java.io.PrintStream; PrintStream ps = new PrintStream("D:\\test.txt"); System.setOut(ps); System.out.println("XXX"); 二.java.u

  • 详解Java中的反射机制和动态代理

    一.反射概述 反射机制指的是Java在运行时候有一种自观的能力,能够了解自身的情况为下一步做准备,其想表达的意思就是:在运行状态中,对于任意一个类,都能够获取到这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制.通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以,这是一种动态获取类的信息以及动态调用对象方法的能力. 想要使用反射机制,就必须要先获取到该类

  • 详解处理Java中的大对象的方法

    目录 String中的substring 集合大对象扩容 保持合适的对象粒度 Bitmap 把对象变小 数据的冷热分离 数据双写 写入 MQ 分发 使用 Binlog 同步 思维发散 小结 本文我们将讲解一下对于“大对象”的优化.这里的“大对象”,是一个泛化概念,它可能存放在 JVM 中,也可能正在网络上传输,也可能存在于数据库中. 那么为什么大对象会影响我们的应用性能呢? 第一,大对象占用的资源多,垃圾回收器要花一部分精力去对它进行回收: 第二,大对象在不同的设备之间交换,会耗费网络流量,以及

  • 详解Spring中BeanUtils工具类的使用

    目录 简介 Spring的BeanUtils方法 Spring的BeanUtils与Apache的BeanUtils区别 实例 简介 说明 本文介绍Spring的BeanUtils工具类的用法. 我们经常需要将不同的两个对象实例进行属性复制,比如将DO对象进行属性复制到DTO,这种转换最原始的方式就是手动编写大量的 get/set代码,很繁琐.为了解决这一痛点,就诞生了一些方便的类库,常用的有 Apache的 BeanUtils,Spring的 BeanUtils, Dozer,Orika等拷贝

  • 详解java JDK 动态代理类分析(java.lang.reflect.Proxy)

    详解java JDK 动态代理类分析(java.lang.reflect.Proxy) /** * JDK 动态代理类分析(java.lang.reflect.Proxy使用) * * @author 张明学 * */ public class ProxyStudy { @SuppressWarnings("unchecked") public static void main(String[] args) throws Exception { // 动态代理类:通用指定类加载器,和接

  • 详解在java中进行日期时间比较的4种方法

    1. Date.compareTo() java.util.Date提供了在Java中比较两个日期的经典方法compareTo(). 如果两个日期相等,则返回值为0. 如果Date在date参数之后,则返回值大于0. 如果Date在date参数之前,则返回值小于0. @Test void testDateCompare() throws ParseException { SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");

随机推荐