深度剖析 Java 应用诊断利器---Arthas

开源
Arthas 是 Alibaba 开源的 Java 诊断工具,支持 JDK 6+,支持 Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。

前言

在介绍 Arthas 之前,大家肯定经历过生产环境遇到Java服务出现问题,最常见的情况就是调用第三方接口出现异常,正好没有打日志,异常堆栈也无法证明是 「谁的锅」。此时你只能焦头烂额一顿操作也无事无补。早些接触到 Arthas 也就可以轻松解决这类问题,同时还可以帮忙我们排查和解决很多常见远程服务的问题。

Arthas(阿尔萨斯)

Arthas 是 Alibaba 开源的 Java 诊断工具,支持 JDK 6+,支持 Linux/Mac/Windows,采用命令行交互模式,同时提供丰富的 Tab 自动补全功能,进一步方便进行问题的定位和诊断。

开源地址:https://github.com/alibaba/arthas。

官方文档:https://github.com/alibaba/arthas。

Arthas 可以帮助我们解决哪些问题:

  1. 这个类从哪个 jar 包加载的?为什么会报各种类相关的 Exception?
  2. 我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?
  3. 遇到问题无法在线上 debug,难道只能通过加日志再重新发布吗?
  4. 线上遇到某个用户的数据处理有问题,但线上同样无法 debug,线下无法重现!
  5. 是否有一个全局视角来查看系统的运行状况?
  6. 有什么办法可以监控到 JVM 的实时运行状态?
  7. 怎么快速定位应用的热点,生成火焰图?

使用 arthas(阿尔萨斯)

采用命令行交互模式,同时提供丰富的 Tab 自动补全功能

1、 安装 arthas

curl -O https://arthas.aliyun.com/arthas-boot.jar
java -jar arthas-boot.jar

「注意可能遇到的的问题:」

  • 执行该程序的用户需要和目标进程具有相同的权限。比如以admin用户来执行:sudo su admin && java -jar arthas-boot.jar 或 sudo -u admin -EH java -jar arthas-boot.jar。
  • 如果attach不上目标进程,可以查看~/logs/arthas/ 目录下的日志。
  • java -jar arthas-boot.jar -h 打印更多参数信息。

2、 选择应用java进程

java -jar arthas-boot.jar
# 选择服务序列,可以通过 java -jar arthas-boot.jar -h 打印更多参数信息

这边遇到报错提示**Can not find tools.**,指定本地jdk全路径执行即可:Such as /opt/jdk/bin/java -jar arthas-boot.jar。

/Library/Java/JavaVirtualMachines/jdk1.8.0_281.jdk/Contents/Home/bin/java -jar arthas-boot.jar

「看到这个界面就可以开始你的操作了」

3、 Arthas web console

「Arthas」 目前支持 Web Console,在成功启动连接进程之后就已经自动启动,可以直接访问 http://127.0.0.1:8563/ 访问,页面上的操作模式和控制台完全一样。

4、常用命令

下面列举一些 「Arthas」 的常用命令,后面会介绍一些常用的命令。后续的命令介绍内容有些生硬,可以先收藏起来大致了解每个命令的作用,未来遇到至少还是有手段可以排查。

(1) dashboard 命令

输入dashboard,按回车/enter,会展示当前进程的信息,按ctrl+c可以中断执行。

(2) thread 命令

查看当前线程信息,查看线程的堆栈。

  • -i: 指定时间内采集。
thread -i 2000

  • -n: 找出 cpu 使用率最高的几个线程。
thread -n 3
[arthas@1]$ thread -n 3
"C1 CompilerThread1" [Internal] cpuUsage=2.59% deltaTime=5ms time=18214ms
"arthas-command-execute" Id=2261 cpuUsage=0.81% deltaTime=1ms time=119ms RUNNABLE
at sun.management.ThreadImpl.dumpThreads0(Native Method)
at sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:448)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.processTopBusyThreads(ThreadCommand.java:206)
at com.taobao.arthas.core.command.monitor200.ThreadCommand.process(ThreadCommand.java:122)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.process(AnnotatedCommandImpl.java:82)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl.access$100(AnnotatedCommandImpl.java:18)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:111)
at com.taobao.arthas.core.shell.command.impl.AnnotatedCommandImpl$ProcessHandler.handle(AnnotatedCommandImpl.java:108)
at com.taobao.arthas.core.shell.system.impl.ProcessImpl$CommandProcessTask.run(ProcessImpl.java:385)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
"C2 CompilerThread0" [Internal] cpuUsage=0.31% deltaTime=0ms time=94495ms
  • -b: 找到持有锁的线程,有时候请求后,一直卡住,那么可以使用该方式去查找持有锁的线程。注意该方式不支持显示锁也就是lock接口的。
thread -b
[arthas@1]$ thread -b
No most blocking thread found!

(3) watch 命令

这个命令也是最常用、最好用的命令之一,方法执行数据观测。可以观察远程服务器方法的调用出入参、异常情况。

常用参数:

  • -x: 指定输出结果的属性遍历深度,默认为 1。
  • -b: 在「方法调用之前」观察。
  • -e: 在「方法异常之后」观察。
  • -s: 在「方法返回之后」观察。
  • -f: 在「方法结束之后」(正常返回和异常返回)观察。

观察方法出参和返回值。

[arthas@1]$ watch com.xx.actionlog.impl.ActionLogConfigApiImpl listTopics  "{params,returnObj}" -x 2
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 238 ms, listenerId: 6
method=com.xx.actionlog.impl.ActionLogConfigApiImpl.listTopics location=AtExit
ts=2021-05-21 14:43:01; [cost=135.092231ms] result=@ArrayList[
@Object[][
@String[K8SOFFICE],
@String[default],
],
@ArrayList[
@String[orders],
@String[orderlogs],
@String[operationlogs],
@String[store],
@String[stores],
@String[place],
@String[tag],
@String[channel],
@String[suppliers],
@String[auth],
@String[site],
],
]

观察方法入参。

[arthas@1]$ watch com.xx.actionlog.impl.ActionLogConfigApiImpl listTopics  "{params,returnObj}" -x 2 -b
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 209 ms, listenerId: 7
method=com.xx.actionlog.impl.ActionLogConfigApiImpl.listTopics location=AtEnter
ts=2021-05-21 14:55:34; [cost=0.054197ms] result=@ArrayList[
@Object[][
@String[K8SOFFICE],
@String[default],
],
null,
]

同时观察方法调用前和方法返回后。

[arthas@1]$ watch com.xx.actionlog.impl.ActionLogConfigApiImpl listTopics  "{params,target,returnObj}" -x 2 -b -s -n 2
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 190 ms, listenerId: 8
method=com.xx.actionlog.impl.ActionLogConfigApiImpl.listTopics location=AtEnter
ts=2021-05-21 14:57:18; [cost=0.035688ms] result=@ArrayList[
@Object[][
@String[K8SOFFICE],
@String[default],
],
@ActionLogConfigApiImpl[
log=@Logger[Logger[com.xx.actionlog.impl.ActionLogConfigApiImpl]],
DEFAULT_CLUSTER=@String[default],
DEFAULT_NAMESPACE=@String[application],
DEFAULT_ACTION_LOG_NAMESPACE=@String[actionLogConfig],
apolloOperationService=@ApolloOperationService[com.xx.actionlog.service.ApolloOperationService@9470ab3],
$jacocoData=@boolean[][isEmpty=false;size=91],
],
null,
]
method=com.xx.actionlog.impl.ActionLogConfigApiImpl.listTopics location=AtExit
ts=2021-05-21 14:57:18; [cost=1.4527299465320627E10ms] result=@ArrayList[
@Object[][
@String[K8SOFFICE],
@String[default],
],
@ActionLogConfigApiImpl[
log=@Logger[Logger[com.xx.actionlog.impl.ActionLogConfigApiImpl]],
DEFAULT_CLUSTER=@String[default],
DEFAULT_NAMESPACE=@String[application],
DEFAULT_ACTION_LOG_NAMESPACE=@String[actionLogConfig],
apolloOperationService=@ApolloOperationService[com.xx.actionlog.service.ApolloOperationService@9470ab3],
$jacocoData=@boolean[][isEmpty=false;size=91],
],
@ArrayList[
@String[orders],
@String[orderlogs],
@String[operationlogs],
@String[store],
@String[stores],
@String[place],
@String[tag],
@String[channel],
@String[suppliers],
@String[auth],
@String[site],
],
]
Command execution times exceed limit: 2, so command will exit. You can set it with -n option.

(4) sc 命令

Search-Class英文的缩写,用于查看JVM已加载的类信息。

常用参数:

  • -d: 参数用于输出详细的类相关信息(类全限定名,存放路径,接口,注解,继承父类,类加载器等),支持模糊查询。
  • -f: 参数需要配合 -d 命令一起使用, 在上述类信息中加入字段信息,包括权限、类型、名字。
sc -d -f *TableInfoServiceImpl
[arthas@1]$ sc -d -f *TableInfoServiceImpl
class-info com.xx.consumer.actionlog.service.impl.TableInfoServiceImpl
code-source file:/app/action-log-consumer.jar!/BOOT-INF/classes!/
name com.xx.consumer.actionlog.service.impl.TableInfoServiceImpl
isInterface false
isAnnotation false
isEnum false
isAnonymousClass false
isArray false
isLocalClass false
isMemberClass false
isPrimitive false
isSynthetic false
simple-name TableInfoServiceImpl
modifier public
annotation org.springframework.stereotype.Service
interfaces com.xx.consumer.actionlog.service.TableInfoService
super-class +-java.lang.Object
class-loader +-org.springframework.boot.loader.LaunchedURLClassLoader@7fad8c79
+-sun.misc.Launcher$AppClassLoader@18b4aac2
+-sun.misc.Launcher$ExtClassLoader@63c4310c
classLoaderHash 7fad8c79
fields name log
type org.slf4j.Logger
modifier final,private,static
value Logger[com.xx.consumer.actionlog.service.impl.TableInfoServiceIm
pl]

name actionLogConfigProperties
type com.xx.consumer.actionlog.properties.ActionLogConfigProperties
modifier private
annotation org.springframework.beans.factory.annotation.Autowired

name $jacocoData
type []
modifier private,static,transient
value [Z@4494fa9e


Affect(row-cnt:1) cost in 47 ms.

其他参数:

  • -E: 开启正则表达式匹配,默认为通配符匹配。
  • -c: 类名表达式匹配。

(5) sm 命令

Search-Method英文的缩写,用于查看已加载类的方法信息。

常用参数:

  • -d: 方法详情。
sm -d *ActionLogServiceImpl process
[arthas@1]$ sm -d *ActionLogServiceImpl process
declaring-class com.xx.consumer.actionlog.service.impl.ActionLogServiceImpl
method-name process
modifier public
annotation
parameters java.lang.String
return void
exceptions
classLoaderHash 7fad8c79
Affect(row-cnt:1) cost in 48 ms.

其他参数:

  • -E: 开启正则表达式匹配,默认为通配符匹配。
  • -c: 类名表达式匹配。

(6) jad 命令

反编译指定已加载类的源码。

jad *TableInfoServiceImpl
[arthas@1]$ jad *TableInfoServiceImpl
ClassLoader:
+-org.springframework.boot.loader.LaunchedURLClassLoader@7fad8c79
+-sun.misc.Launcher$AppClassLoader@18b4aac2
+-sun.misc.Launcher$ExtClassLoader@63c4310c
Location:
file:/app/action-log-consumer.jar!/BOOT-INF/classes!/
/*
* Decompiled with CFR.
*
* Could not load the following classes:
* com.xx.consumer.actionlog.properties.ActionLogConfigProperties
* com.xx.consumer.actionlog.properties.ActionLogConfigProperties$ActionLogConfigItem
* com.xx.consumer.actionlog.properties.AttentionFieldConfig
* com.xx.consumer.actionlog.service.TableInfoService
* org.slf4j.Logger
* org.slf4j.LoggerFactory
* org.springframework.beans.factory.annotation.Autowired
* org.springframework.stereotype.Service
*/
package com.xx.consumer.actionlog.service.impl;

import com.xx.consumer.actionlog.properties.ActionLogConfigProperties;
import com.xx.consumer.actionlog.properties.AttentionFieldConfig;
import com.xx.consumer.actionlog.service.TableInfoService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class TableInfoServiceImpl
implements TableInfoService {
private static final Logger log;
@Autowired
private ActionLogConfigProperties actionLogConfigProperties;
private static transient /* synthetic */ boolean[] $jacocoData;
public TableInfoServiceImpl() {
boolean[] blArray = TableInfoServiceImpl.$jacocoInit();
blArray[0] = true;
}
/*
* WARNING - void declaration
*/
public String getColumnCommentByTableNameAndColumnName(String string, String string2) {
String desc;
void columnName;
boolean[] blArray = TableInfoServiceImpl.$jacocoInit();
/*18*/ void var4_4 = columnName;
try {
void tableName;
blArray[1] = true;
/*20*/ desc = ((AttentionFieldConfig)((ActionLogConfigProperties.ActionLogConfigItem)this.actionLogConfigProperties.getConfig().get(tableName)).getAttentionFields().get(columnName)).getDesc();
/*23*/ blArray[2] = true;
}
catch (Exception exception) {
void e;
blArray[3] = true;
/*22*/ log.warn(e.getMessage(), (Throwable)e);
blArray[4] = true;
}
blArray[5] = true;
return desc;
}
static {
boolean[] blArray = TableInfoServiceImpl.$jacocoInit();
/*10*/ log = LoggerFactory.getLogger(TableInfoServiceImpl.class);
blArray[6] = true;
}
private static /* synthetic */ boolean[] $jacocoInit() {
boolean[] blArray = $jacocoData;
if ($jacocoData == null) {
Object[] objectArray = new Object[]{883735039782912886L, "com/xx/consumer/actionlog/service/impl/TableInfoServiceImpl", 7};
UnknownError.$jacocoAccess.equals(objectArray);
blArray = $jacocoData = (boolean[])objectArray[0];
}
return blArray;
}
}
Affect(row-cnt:1) cost in 253 ms.

(7) jvm 命令

输出 jvm 相关信息,包括加载类的路径,启动类路径,加载类个数等等。

(8) trace 命令

方法内部调用路径,并输出方法路径上的每个节点上耗时,「用于接口性能定位和调优的时候使用」。

常用参数:

  • -n: 有时候请求量太大,我们不需要每个请求调用时间,那么可以使用这个参数,指定次数调用后结束。
trace *ActionLogConfigApiImpl listTopics -n 2
[arthas@1]$ trace *ActionLogConfigApiImpl listTopics -n 2
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 237 ms, listenerId: 3
`---ts=2021-05-21 14:22:43;thread_name=http-nio-8047-exec-5;id=59;is_daemon=true;priority=5;TCCL=org.springframework.boot.loader.LaunchedURLClassLoader@7fad8c79
`---[158.020381ms] com.xx.actionlog.impl.ActionLogConfigApiImpl:listTopics()
+---[0.063066ms] com.xx.actionlog.impl.ActionLogConfigApiImpl:$jacocoInit() #25
+---[0.035828ms] com.xx.utils.StringUtils:isEmpty() #108
+---[0.02172ms] com.xx.utils.StringUtils:isEmpty() #114
`---[157.534007ms] com.xx.actionlog.service.ApolloOperationService:listKafkaTopics() #117

`---ts=2021-05-21 14:22:51;thread_name=http-nio-8047-exec-9;id=5d;is_daemon=true;priority=5;TCCL=org.springframework.boot.loader.LaunchedURLClassLoader@7fad8c79
`---[173.617716ms] com.xx.actionlog.impl.ActionLogConfigApiImpl:listTopics()
+---[0.025143ms] com.xx.actionlog.impl.ActionLogConfigApiImpl:$jacocoInit() #25
+---[0.023677ms] com.xx.utils.StringUtils:isEmpty() #108
+---[0.017739ms] com.xx.utils.StringUtils:isEmpty() #114
`---[173.398065ms] com.xx.actionlog.service.ApolloOperationService:listKafkaTopics() #117

Command execution times exceed limit: 2, so command will exit. You can set it with -n option.

(9) stack 命令

输出当前方法被调用的调用路径,「当前方法可能会调用不同路径的时候,可以使用该命令跟踪调用链路」。

常用参数:

  • -n: 指定结束次数,达到次数则自动退出,不继续监听。
stack *ActionLogConfigApiImpl listTopics -n 1

查看 ActionLogConfigApiImpl 类 listTopics 方法调用链路。

[arthas@1]$ stack *ActionLogConfigApiImpl listTopics -n 1
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 545 ms, listenerId: 1
ts=2021-05-21 13:51:59;thread_name=http-nio-8047-exec-2;id=56;is_daemon=true;priority=5;TCCL=org.springframework.boot.loader.LaunchedURLClassLoader@7fad8c79
@com.xx.actionlog.impl.ActionLogConfigApiImpl.listTopics()
at org.apache.dubbo.common.bytecode.Wrapper3.invokeMethod(Wrapper3.java:-1)
at org.apache.dubbo.rpc.proxy.javassist.JavassistProxyFactory$1.doInvoke(JavassistProxyFactory.java:47)
at org.apache.dubbo.rpc.proxy.AbstractProxyInvoker.invoke(AbstractProxyInvoker.java:84)
at com.xx.apache.dubbo.filter.xxExceptionFilter.invoke(xxExceptionFilter.java:53)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:81)
at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:89)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:81)
at com.alibaba.dubbo.rpc.Invoker$CompatibleInvoker.invoke(Invoker.java:55)
at com.xx.zipkin.dubbo.ZipkinDubboFilter.invoke(ZipkinDubboFilter.java:84)
at com.alibaba.dubbo.rpc.Filter.invoke(Filter.java:29)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:81)
at org.apache.dubbo.rpc.filter.TimeoutFilter.invoke(TimeoutFilter.java:44)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:81)
at org.apache.dubbo.rpc.protocol.dubbo.filter.TraceFilter.invoke(TraceFilter.java:77)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:81)
at org.apache.dubbo.rpc.filter.ExecuteLimitFilter.invoke(ExecuteLimitFilter.java:56)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:81)
at org.apache.dubbo.rpc.filter.ContextFilter.invoke(ContextFilter.java:118)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:81)
at org.apache.dubbo.rpc.filter.GenericFilter.invoke(GenericFilter.java:152)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:81)
at org.apache.dubbo.rpc.filter.ClassLoaderFilter.invoke(ClassLoaderFilter.java:38)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:81)
at org.apache.dubbo.rpc.filter.EchoFilter.invoke(EchoFilter.java:41)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.invoke(ProtocolFilterWrapper.java:81)
at org.apache.dubbo.rpc.protocol.injvm.InjvmInvoker.doInvoke(InjvmInvoker.java:63)
at org.apache.dubbo.rpc.protocol.AbstractInvoker.invoke(AbstractInvoker.java:162)
at org.apache.dubbo.rpc.protocol.AsyncToSyncInvoker.invoke(AsyncToSyncInvoker.java:52)
at org.apache.dubbo.monitor.support.MonitorFilter.invoke(MonitorFilter.java:89)
at org.apache.dubbo.rpc.protocol.ProtocolFilterWrapper$1.in
voke(ProtocolFilterWrapper.java:81)
at com.alibaba.dubbo.rpc.Invoker$CompatibleInvoker.invoke(Invoker.java:55)
at com.xx.zipkin.dubbo.ZipkinDubboFilter.invoke(ZipkinDubboFilter.java:84)
....
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:109)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.springframework.boot.actuate.autoconfigure.MetricsFilter.doFilterInternal(MetricsFilter.java:100)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at com.xx.web.filters.SimpleCORSFilter.doFilter(SimpleCORSFilter.java:38)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:137)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
at org.apache.catalina.valves.RemoteIpValve.invoke(RemoteIpValve.java:679)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:798)
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:808)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498)
at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Thread.java:748)
Command execution times exceed limit: 1, so command will exit. You can set it with -n option.

(10) stack 命令

执行ognl表达式。

调用静态函数。

$ ognl '@java.lang.System@out.println("hello")'
null

查看静态变量值(注意hashcode是变化的,需要先查看当前的ClassLoader信息,提取对应ClassLoader的hashcode)。

通过hashcode指定ClassLoader:

[arthas@1]$ classloader -t
+-BootstrapClassLoader
+-sun.misc.Launcher$ExtClassLoader@7611dd8b
+-com.taobao.arthas.agent.ArthasClassloader@17e023f0
+-sun.misc.Launcher$AppClassLoader@18b4aac2
+-org.springframework.boot.loader.LaunchedURLClassLoader@7fad8c79
+-com.alibaba.fastjson.util.ASMClassLoader@4be7162b
+-TomcatEmbeddedWebappClassLoader
context: ROOT
delegate: true
----------> Parent Classloader:
org.springframework.boot.loader.LaunchedURLClassLoader@7fad8c79

Affect(row-cnt:7) cost in 23 ms.
  • -c: 执行表达式的 ClassLoader 的 hashcode,默认值是SystemClassLoader。
[arthas@1]$ ognl -c 7fad8c79 '@com.xx.actionlog.impl.ActionLogConfigApiImpl@DEFAULT_CLUSTER'
@String[default]
责任编辑:姜华 来源: Java架构师进阶编程
相关推荐

2023-03-03 09:33:45

ArthasJava诊断工具

2023-04-11 07:46:11

平台arthas线诊断

2010-02-04 14:01:44

Android应用

2010-02-01 14:05:03

2010-01-26 17:16:33

C++应用程序

2010-07-12 21:44:51

HART协议

2010-03-04 10:11:17

Android手机系统

2010-08-26 15:44:20

CSSexpression

2013-04-12 15:51:55

2012-02-08 10:37:42

Java反射

2017-09-21 12:29:58

深度学习TensorFlow智能终端

2022-09-27 18:56:28

ArrayList数组源代码

2024-02-05 19:06:04

DartVMGC流程

2009-06-22 13:40:00

RubyJava

2021-06-01 09:29:43

ArthasJVM内存

2010-02-04 15:38:39

Android 手机

2020-04-01 10:28:12

Apache HBas数据结构算法

2014-10-17 09:30:38

2010-03-05 16:38:30

2010-02-02 15:25:35

Python语法
点赞
收藏

51CTO技术栈公众号