Arthas直接执行Spring Context中的函数
小轲 Lv3

简介

Arthas提供了非常丰富的关于调用拦截的命令,比如 trace/watch/monitor/tt 。但是很多时候我们在排查问题时,需要更多的线索,并不只是函数的参数和返回值。
比如在一个Spring应用里,想获取到Spring context里的其它bean。如果能随意获取到Spring bean,那就可以“为所欲为”了。
下面介绍如何利用Arthas获取到Spring context。

操作步骤

Spring MVC应用,请求会经过一系列的Spring Bean处理,那么我们可以在Spring MVC的类里拦截到一些请求。
使用Arthas Attach成功之后,执行tt命令来记录RequestMappingHandlerAdapter#invokeHandlerMethod的请求,可以直接获取到Spring context了就

1. 使用tt命令监控Spring RequestMappingHandlerAdapter中的类

执行下列命令后,你需要做两件事

  1. 触发http请求,让tt命令监听到RequestMappingHandlerAdapter
  2. 监控控制台,看到下方有一条记录即可。获取到下列结果的INDEX值,比如1000
    1
    2
    3
    4
    5
    6
    7
    8
    [arthas@1]$ tt -t org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod
    Press Q or Ctrl+C to abort.
    结果:
    Affect(class count: 1 , method count: 1) cost in 323 ms, listenerId: 2
    INDEX TIMESTAMP COST(ms) IS-RET IS-EXP OBJECT CLASS METHOD
    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
    1000 2023-04-13 10:47:54 19.308463 true false 0x39ae0bff RequestMappingHandlerAdapter invokeHandlerMethod
    1001 2023-04-13 10:47:54 34.872646 true false 0x39ae0bff RequestMappingHandlerAdapter invokeHandlerMethod
    目前已经监听到了spring的bean执行了,下面来获取spring的context

2. 获取Spring的context

可以用tt命令的-i参数来指定index,并且用-w参数来执行ognl表达式来获取spring context:

1
2
3
tt -i INDEX -w 'target.getApplicationContext()'
..........结果忽略
Affect(row-cnt:1) cost in 7 ms.

3. 从Spring context里获取任意bean

获取到spring context之后,就可以获取到任意的bean了,比如获取到logBusinessOperateServiceImpl,并调用reloadEntityFields()函数:

1
2
3
4
[arthas@1]$ tt -i 1000 -w 'target.getApplicationContext().getBean("logBusinessOperateServiceImpl").reloadEntityFields()'
结果:
null
Affect(row-cnt:1) cost in 30 ms.

如果需要传递参数的函数,则直接在调用方法的参数里直接写即可(按照方法重载的规则),例如reloadEntityFields('admin',123,3.7F)

更多的思路

在很多代码里都有static函数或者static holder类,顺滕摸瓜,可以获取很多其它的对象。比如在Dubbo里通过SpringExtensionFactory获取spring context:

1
2
3
4
5
6
$ ognl '#context=@com.alibaba.dubbo.config.spring.extension.SpringExtensionFactory@contexts.iterator.next, 
#context.getBean("userServiceImpl").findUser(1)'
@User[
id=@Integer[1],
name=@String[Deanna Borer],
]

帮助地址

  1. 原链接,GitHub issues: https://github.com/alibaba/arthas/issues/482,具体详细内容可在里面讨论。
  2. 官方提供Demo: https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-arthas-spring-boot
  3. Arthas快速开始:https://arthas.aliyun.com/doc/quick-start.html
 评论