# java-arthas **Repository Path**: codepilipala/java-arthas ## Basic Information - **Project Name**: java-arthas - **Description**: arthas使用 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2024-09-18 - **Last Updated**: 2024-09-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README #### 安装使用 ```text 下载arthas wget https://arthas.aliyun.com/arthas-boot.jar 下载jdk17 wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz 解压jdk17 tar xf /home/jdk17/jdk-17_linux-x64_bin.tar.gz 指定jdk17运行arthas /home/jdk17/jdk-17.0.12/bin/java -jar arthas-boot.jar ``` #### arthas基本和常用命令 ```text version 打印当前arthas版本 session 显示当前会话 pwd 当前工作目录 history 历史命令 help 帮助 quit 退出当前会话,但不影响其他会话 stop 终止Arthas服务器,所有会话被销毁 reset 重置所有增强类。当arthas服务器被关闭时,所有增强类都会被重置stop echo 将参数写入标准输出,echo '...' cls 清除屏幕 cat 打印文件 base64 对字符串或文件进行base64编码 monitor 监视方法执行统计信息 watch 显示指定方法调用的输入/输出参数,返回对象和抛出异常 getstatic 获取静态属性值 vmtool jvm工具,可以调用实例方法等 sc 检查jvm加载的类信息 sm - 检查已加载类的方法信息 ognl 执行ognl表达式 thread 查看当前线程信息 jad 反编译指定类 mc - 内存编译器,将.java文件编译成.class内存中的文件 jvm 查看jvm信息 logger-打印记录器信息,更新记录器级别 mbean - 显示 Mbean 信息 memory-显示 JVM 内存信息 perfcounter-显示 JVM 性能计数器信息 sysenv — 查看系统环境变量 sysprop——查看/修改系统属性 dump - 将加载的类以字节码形式转储到指定位置 ``` #### sm 检查已知加载类的方法信息 ```text [arthas@51644]$ sm com.example.service.MemberService com.example.service.MemberService ()V com.example.service.MemberService init()V com.example.service.MemberService getMembers(Lcom/example/model/MemberQuery;)Ljava/util/List; com.example.service.MemberService getMembers(Ljava/lang/Integer;)Ljava/util/List; com.example.service.MemberService getMember(Ljava/lang/Long;)Lcom/example/model/Member; com.example.service.MemberService getMemberById(Ljava/lang/Integer;)Lcom/example/model/Member; com.example.service.MemberService getMemberId(Ljava/lang/String;)Ljava/lang/Long; com.example.service.MemberService lambda$getMemberId$4(Ljava/lang/String;Lcom/example/model/Member;)Z com.example.service.MemberService lambda$getMembers$3(Lcom/example/model/MemberQuery;Lcom/example/model/Member;)Z com.example.service.MemberService lambda$getMembers$2(Ljava/lang/Integer;Lcom/example/model/Member;)Z com.example.service.MemberService lambda$getMember$1(Ljava/lang/Long;Lcom/example/model/Member;)Z com.example.service.MemberService lambda$getMemberById$0(Ljava/lang/Integer;Lcom/example/model/Member;)Z Affect(row-cnt:12) cost in 24 ms. ``` #### jad反编译指定类 ```text [arthas@51644]$ jad com.example.service.MemberService ClassLoader: +-org.springframework.boot.loader.launch.LaunchedClassLoader@5305068a +-jdk.internal.loader.ClassLoaders$AppClassLoader@46fbb2c1 +-jdk.internal.loader.ClassLoaders$PlatformClassLoader@17e29da5 Location: nested:/home/arthas/arthas-test.jar/!BOOT-INF/classes/!/ /* * Decompiled with CFR. * * Could not load the following classes: * com.example.model.Member * com.example.model.MemberQuery * jakarta.annotation.PostConstruct * org.springframework.stereotype.Service */ package com.example.service; import com.example.model.Member; import com.example.model.MemberQuery; import jakarta.annotation.PostConstruct; import java.util.ArrayList; import java.util.List; import org.springframework.stereotype.Service; @Service public class MemberService { private Integer executeCountPrivate = 0; public Integer executeCountPublic = 0; private static Integer executeStaticCountPrivate = 0; public static Integer executeStaticCountPublic = 0; private static List memberList = new ArrayList(); @PostConstruct public void init() { /*70*/ memberList.add(new Member(Long.valueOf(1L), "member1", "member1@naver.com", Integer.valueOf(1))); /*71*/ memberList.add(new Member(Long.valueOf(2L), "member2", "member2@naver.com", Integer.valueOf(1))); /*72*/ memberList.add(new Member(Long.valueOf(3L), "member3", "member3@naver.com", Integer.valueOf(1))); /*73*/ memberList.add(new Member(Long.valueOf(4L), "member4", "member4@naver.com", Integer.valueOf(1))); /*74*/ memberList.add(new Member(Long.valueOf(5L), "member5", "member5@naver.com", Integer.valueOf(1))); /*75*/ memberList.add(new Member(Long.valueOf(6L), "member6", "member6@naver.com", Integer.valueOf(1))); /*76*/ memberList.add(new Member(Long.valueOf(7L), "member7", "member7@naver.com", Integer.valueOf(2))); /*77*/ memberList.add(new Member(Long.valueOf(8L), "member8", "member8@naver.com", Integer.valueOf(2))); /*78*/ memberList.add(new Member(Long.valueOf(9L), "member9", "member9@naver.com", Integer.valueOf(2))); } public List getMembers(MemberQuery memberQuery) { /*42*/ return memberList.stream().filter(member -> { /*44*/ if (memberQuery.id() != null && !memberQuery.id().equals(member.id())) { /*45*/ return false; } /*47*/ if (memberQuery.status() != null && !memberQuery.status().equals(member.status())) { /*48*/ return false; } /*50*/ if (memberQuery.name() != null && !member.name().contains(memberQuery.name())) { /*51*/ return false; } /*53*/ return memberQuery.mobilePhone() == null || member.mobilePhone().contains(memberQuery.mobilePhone()); }).toList(); } public List getMembers(Integer status) { /*36*/ return memberList.stream().filter(member -> member.status().equals(status)).toList(); } public Member getMember(Long id) { /*30*/ return memberList.stream().filter(member -> member.id().equals(id)).findFirst().orElse(null); } public Member getMemberById(Integer id) { /*22*/ executeStaticCountPrivate = executeStaticCountPrivate + 1; /*23*/ executeStaticCountPublic = executeStaticCountPublic + 1; /*24*/ return memberList.stream().filter(member -> member.id().equals(id)).findFirst().orElse(null); } public Long getMemberId(String name) { /*62*/ return memberList.stream().filter(member -> member.name().equals(name)).map(Member::id).findFirst().orElse(null); } } Affect(row-cnt:1) cost in 863 ms. ``` #### base64 ```text 新建一个明文字符串到文件进行编码 [arthas@51644]$ echo '213456' > 11.txt [arthas@51644]$ base64 11.txt MjEzNDU2Cg== 新建一个编码后的文本到文件,进行解码 [arthas@51644]$ echo 'MjEzNDU2Cg==' > 22.txt [arthas@51644]$ base64 -d 22.txt 213456 ``` #### 监视功能 monitor ```text class-pattern 类名表达式匹配 method-pattern 方法名表达式匹配 [E] 开启正则表达式匹配,默认为通配符匹配 [c:] 统计周期,默认值为120秒 默认统计60s monitor com.example.service.MemberService getMember 自定义统计时间 monitor com.example.service.MemberService getMember -c 5 ``` ![img_1.png](img_1.png) #### 检测函数调用返回值 ```text class-pattern 类名表达式匹配 method-pattern 方法名表达式匹配 express 观察表达式 condition-express 条件表达式 [b] 在方法调用之前观察before [e] 在方法异常之后观察 exception [s] 在方法返回之后观察 success [f] 在方法结束之后(正常返回和异常返回)观察 finish [E] 开启正则表达式匹配,默认为通配符匹配 [x:] 指定输出结果的属性遍历深度,默认为 1 ``` 1. 查看请求前参数,如果params不指定下标,好像是拿不到请求参数。这是获取请求前参数,所以返回参数为null ```shell [arthas@51644]$ watch com.example.service.MemberService getMemberId "{params[0],returnObj}" -b Press Q or Ctrl+C to abort. Affect(class count: 1 , method count: 1) cost in 33 ms, listenerId: 34 method=com.example.service.MemberService.getMemberId location=AtEnter ts=2024-09-18 01:21:51; [cost=0.023436ms] result=@ArrayList[ @String[member3], null, ] ``` 2. 查看请求异常 3. 查看请求结束 ```shell [arthas@51644]$ watch com.example.service.MemberService getMemberId "{params[0],returnObj}" -s Press Q or Ctrl+C to abort. Affect(class count: 1 , method count: 1) cost in 33 ms, listenerId: 35 method=com.example.service.MemberService.getMemberId location=AtExit ts=2024-09-18 01:22:36; [cost=0.43463ms] result=@ArrayList[ @String[member3], @Long[3], ] ``` 4. 查看类变量 需要设置设置深度2 ```shell [arthas@51644]$ watch com.example.service.MemberService getMemberId "{target}" -x 2 Press Q or Ctrl+C to abort. Affect(class count: 1 , method count: 1) cost in 34 ms, listenerId: 36 method=com.example.service.MemberService.getMemberId location=AtExit ts=2024-09-18 01:24:31; [cost=0.397346ms] result=@ArrayList[ @MemberService[ executeCountPrivate=@Integer[0], executeCountPublic=@Integer[0], executeStaticCountPrivate=@Integer[65340], executeStaticCountPublic=@Integer[65340], memberList=@ArrayList[isEmpty=false;size=9], ], ] ``` 5. 查看类全部变量值 需要设置设置深度3 ```shell [arthas@51644]$ watch com.example.service.MemberService getMemberId "{target}" -x 3 Press Q or Ctrl+C to abort. Affect(class count: 1 , method count: 1) cost in 33 ms, listenerId: 37 method=com.example.service.MemberService.getMemberId location=AtExit ts=2024-09-18 01:25:11; [cost=0.451643ms] result=@ArrayList[ @MemberService[ executeCountPrivate=@Integer[0], executeCountPublic=@Integer[0], executeStaticCountPrivate=@Integer[65348], executeStaticCountPublic=@Integer[65348], memberList=@ArrayList[ @Member[Member[id=1, name=member1, mobilePhone=member1@naver.com, status=1]], @Member[Member[id=2, name=member2, mobilePhone=member2@naver.com, status=1]], @Member[Member[id=3, name=member3, mobilePhone=member3@naver.com, status=1]], @Member[Member[id=4, name=member4, mobilePhone=member4@naver.com, status=1]], @Member[Member[id=5, name=member5, mobilePhone=member5@naver.com, status=1]], @Member[Member[id=6, name=member6, mobilePhone=member6@naver.com, status=1]], @Member[Member[id=7, name=member7, mobilePhone=member7@naver.com, status=2]], @Member[Member[id=8, name=member8, mobilePhone=member8@naver.com, status=2]], @Member[Member[id=9, name=member9, mobilePhone=member9@naver.com, status=2]], ], ], ] ``` 6. 获取类指定变量值,设置深度2 ```shell [arthas@51644]$ watch com.example.service.MemberService getMemberId "{target.executeCountPrivate}" -x 2 Press Q or Ctrl+C to abort. Affect(class count: 1 , method count: 1) cost in 33 ms, listenerId: 38 method=com.example.service.MemberService.getMemberId location=AtExit ts=2024-09-18 01:25:41; [cost=0.405499ms] result=@ArrayList[ @Integer[0], ] ``` 7. 查看类静态变量 ```shell [arthas@51644]$ getstatic com.example.service.MemberService memberList field: memberList @ArrayList[ @Member[Member[id=1, name=member1, mobilePhone=member1@naver.com, status=1]], @Member[Member[id=2, name=member2, mobilePhone=member2@naver.com, status=1]], @Member[Member[id=3, name=member3, mobilePhone=member3@naver.com, status=1]], @Member[Member[id=4, name=member4, mobilePhone=member4@naver.com, status=1]], @Member[Member[id=5, name=member5, mobilePhone=member5@naver.com, status=1]], @Member[Member[id=6, name=member6, mobilePhone=member6@naver.com, status=1]], @Member[Member[id=7, name=member7, mobilePhone=member7@naver.com, status=2]], @Member[Member[id=8, name=member8, mobilePhone=member8@naver.com, status=2]], @Member[Member[id=9, name=member9, mobilePhone=member9@naver.com, status=2]], ] Affect(row-cnt:1) cost in 4 ms ``` 8. 获取类的实例 ```shell [arthas@51644]$ vmtool --action getInstances --className com.example.service.MemberService -express 'instances[0]' @MemberService[ executeCountPrivate=@Integer[0], executeCountPublic=@Integer[0], executeStaticCountPrivate=@Integer[65689], executeStaticCountPublic=@Integer[65689], memberList=@ArrayList[isEmpty=false;size=9], ] ``` 9. 调用类实例方法 ```shell 先传一个不存在的ID去调用 [arthas@51644]$ vmtool --action getInstances --className com.example.service.MemberService -express 'instances[0].getMemberById(33)' null 传一个实际存在的ID去调用 [arthas@51644]$ vmtool --action getInstances --className com.example.service.MemberService -express 'instances[0].getMemberById(1)' @Member[ id=@Long[1], name=@String[member1], mobilePhone=@String[member1@naver.com], status=@Integer[1], ] ``` 10. sc查看类详情信息 ```shell [arthas@51644]$ sc -d com.example.service.MemberService class-info com.example.service.MemberService code-source nested:/home/arthas/arthas-test.jar/!BOOT-INF/classes/!/ name com.example.service.MemberService isInterface false isAnnotation false isEnum false isAnonymousClass false isArray false isLocalClass false isMemberClass false isPrimitive false isSynthetic false simple-name MemberService modifier public annotation org.springframework.stereotype.Service interfaces super-class +-java.lang.Object class-loader +-org.springframework.boot.loader.launch.LaunchedClassLoader@5305068a +-jdk.internal.loader.ClassLoaders$AppClassLoader@46fbb2c1 +-jdk.internal.loader.ClassLoaders$PlatformClassLoader@17e29da5 classLoaderHash 5305068a Affect(row-cnt:1) cost in 52 ms. ``` 11. 使用sc + getstatic 指定classloader获取类静态变量值。 如果类被多个classloader所加载,可以使用sc指定classloader以防执行的时候报解析或者找不到的异常 ```shell [arthas@51644]$ getstatic -c 5305068a com.example.service.MemberService memberList field: memberList @ArrayList[ @Member[Member[id=1, name=member1, mobilePhone=member1@naver.com, status=1]], @Member[Member[id=2, name=member2, mobilePhone=member2@naver.com, status=1]], @Member[Member[id=3, name=member3, mobilePhone=member3@naver.com, status=1]], @Member[Member[id=4, name=member4, mobilePhone=member4@naver.com, status=1]], @Member[Member[id=5, name=member5, mobilePhone=member5@naver.com, status=1]], @Member[Member[id=6, name=member6, mobilePhone=member6@naver.com, status=1]], @Member[Member[id=7, name=member7, mobilePhone=member7@naver.com, status=2]], @Member[Member[id=8, name=member8, mobilePhone=member8@naver.com, status=2]], @Member[Member[id=9, name=member9, mobilePhone=member9@naver.com, status=2]], ] Affect(row-cnt:1) cost in 5 ms. ``` 12. 使用sc + ognl 指定classloader获取类静态变量值。但是出于安全原因可以会禁止ognl,ognl是一个强大的表达式语言, 用来获取和设置java属性,列表映射等。它旨在提供一个更高抽象度的语法来对java对象图进行导航。 ```shell [arthas@51644]$ ognl -c 5305068a @com.example.service.MemberService@executeStaticCountPublic @Integer[65788] ```