使用约束

1、需要 jdk,如果部署的应用是jre 运行,需要上传jdk
2、热替换class 同debug 时热替换一样,不能新增方法和字段,否则替换失败。
3、执行arths 的 用户必须与 目标程序运行的用户相同,否则无法连接目标进程

执行
jdkpath/bin/java -jar /path/to/arthas-boot.jar

PS C:\Users\wangchangjin\Downloads\arthas-bin> java -jar .\arthas-boot.jar
[INFO] JAVA_HOME: D:\program\jdk\jdk8_64\jre
[INFO] arthas-boot version: 3.6.7
[INFO] Found existing java process, please choose one and input the serial number of the process, eg : 1. Then hit ENTER.
* [1]: 14256 org.jetbrains.jps.cmdline.Launcher
  [2]: 2352
  [3]: 15080 org.jetbrains.idea.maven.server.RemoteMavenServer36
  [4]: 22684 com.example.demo.DemoApplication
4
[INFO] arthas home: C:\Users\wangchangjin\Downloads\arthas-bin
[INFO] Try to attach process 22684
[INFO] Attach process 22684 success.
[INFO] arthas-client connect 127.0.0.1 3658
  ,---.  ,------. ,--------.,--.  ,--.  ,---.   ,---.
 /  O  \ |  .--. ''--.  .--'|  '--'  | /  O  \ '   .-'
|  .-.  ||  '--'.'   |  |   |  .--.  ||  .-.  |`.  `-.
|  | |  ||  |\  \    |  |   |  |  |  ||  | |  |.-'    |
`--' `--'`--' '--'   `--'   `--'  `--'`--' `--'`-----'

wiki       https://arthas.aliyun.com/doc
tutorials  https://arthas.aliyun.com/doc/arthas-tutorials.html
version    3.6.7
main_class
pid        22684
time       2023-03-26 18:52:42

内存操作

查看类静态变量的值

[arthas@16048]$ getstatic com.example.demo.DemoApplication TEST
field: TEST
@String[TEST]
Affect(row-cnt:1) cost in 24 ms.

修改静态变量

final 修饰的静态变量无法修改

[arthas@22684]$ getstatic com.example.demo.DemoApplication TEST
field: TEST
@String[TEST]
Affect(row-cnt:1) cost in 25 ms.
[arthas@22684]$ ognl '#c=@com.example.demo.DemoApplication@class,#f=#c.getDeclaredField("TEST"),#f.setAccessible(true),#f.set(#c,"modify static private ")'
null
[arthas@22684]$ getstatic com.example.demo.DemoApplication TEST
field: TEST
@String[modify static private ]
Affect(row-cnt:1) cost in 5 ms.
[arthas@22684]$

查看私有属性的值

[arthas@1020]$ vmtool --action getInstances --className com.example.demo.DemoApplication --express 'instances[0].privateF'
@String[111]

修改私有属性

.
[arthas@1020]$ vmtool --action getInstances --className com.example.demo.DemoApplication --express '#val=instances[0],#val.privateF="222"'
vmtool error: By default, strict mode is true, not allowed to set object properties. Want to set object properties, execute `options strict false`
[arthas@1020]$ options strict false
 NAME    BEFORE-VALUE  AFTER-VALUE
-----------------------------------
 strict  true          false
[arthas@1020]$ vmtool --action getInstances --className com.example.demo.DemoApplication --express '#val=instances[0],#val.privateF="222"'
@String[222]
[arthas@1020]$ vmtool --action getInstances --className com.example.demo.DemoApplication --express 'instances[0].privateF'
@String[222]
[arthas@1020]$

获取类的实例调用并调用方法

[arthas@16048]$ vmtool --action getInstances --className com.example.demo.DemoTest
@DemoTest[][
    @DemoTest[com.example.demo.DemoTest@4a37cea],
]

[arthas@16048]$ vmtool --action getInstances --className com.example.demo.DemoTest --express 'instances[0].getAge()'
@Integer[50]

class 替换

与debug比优点,不用重启,方便回退,省下不少时间,限制同debug,替换的class 不能新增方法
stramApi 的lamda 表达式也是算是方法

热替换class

[arthas@16048]$ retransform /DemoTest.class
retransform success, size: 1, classes:
com.example.demo.DemoTest

查看热替换列表

[arthas@16048]$ retransform -l
Id              ClassName       TransformCount  LoaderHash      LoaderClassName
1               com.example.dem 1               null            null
                o.DemoTest

还原热替换的class

[arthas@16048]$ retransform -d 1
[arthas@16048]$ retransform --classPattern com.example.demo.DemoTest
retransform success, size: 1, classes:
com.example.demo.DemoTest

时耗度量

监控方法调用时长

[arthas@21944]$ trace com.example.demo.DemoTest getAge
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 144 ms, listenerId: 1
`---ts=2023-03-26 17:23:33;thread_name=http-nio-8080-exec-1;id=1b;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@50305a
    `---[0.5094ms] com.example.demo.DemoTest:getAge()

监控方法调用入参和返回值

[arthas@21944]$ watch com.example.demo.DemoApplication hello "{params,returnObj}" -x 2
Press Q or Ctrl+C to abort.
Affect(class count: 2 , method count: 1) cost in 71 ms, listenerId: 5
method=com.example.demo.DemoApplication.hello location=AtExit
ts=2023-03-26 17:33:37; [cost=0.1492ms] result=@ArrayList[
    @Object[][
        @String[tom],
    ],
    @String[hello,tom51],
]

-x 表示入参展开层数,默认是1

打印方法调用堆栈

[arthas@21944]$ stack com.example.demo.DemoTest getAge
Press Q or Ctrl+C to abort.
Affect(class count: 1 , method count: 1) cost in 50 ms, listenerId: 6
ts=2023-03-26 17:37:17;thread_name=http-nio-8080-exec-6;id=20;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@50305a
    @com.example.demo.DemoTest.getAge()
        at com.example.demo.DemoApplication.hello(DemoApplication.java:26)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(NativeMethodAccessorImpl.java:-2)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:150)
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:117)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:895)
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:808)
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1072)
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:965)
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006)
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:502)
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883)
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:596)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:209)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201)
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:117)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:178)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:153)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:167)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:90)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:492)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:130)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:93)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:389)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:63)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:926)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1791)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1191)
        at org.apache.tomcat.util.threads.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:659)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.lang.Thread.run(Thread.java:748)

日志

查看日志appenders

[arthas@21944]$ logger
 name                ROOT
 class               ch.qos.logback.classic.Logger
 classLoader         sun.misc.Launcher$AppClassLoader@18b4aac2
 classLoaderHash     18b4aac2
 level               INFO
 effectiveLevel      INFO
 additivity          true
 codeSource          file:/D:/program/maven_repo/ch/qos/logback/logback-classic/1.2.11/logback-classic-1.2.11.jar
 appenders           name            CONSOLE
                     class           ch.qos.logback.core.ConsoleAppender
                     classLoader     sun.misc.Launcher$AppClassLoader@18b4aac2
                     classLoaderHash 18b4aac2
                     target          System.out

更改级别

[arthas@21944]$ logger --name ROOT --level debug
Update logger level success.

参考

官方文档:https://arthas.aliyun.com/

OGNL 表达式官网:https://commons.apache.org/proper/commons-ognl/language-guide.html



本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!