Arthas 是开源的Java诊断工具,通过向目标虚拟机挂载agent,实现热部署,加载,调试等功能。Arthas有非常多的调用拦截等命令,很多时候我们在排查问题时,需要更多的线索,并不只是函数的参数和返回值。tt命令帮助我们获取到spring bean,从而为所欲为。
TimeTunnel的介绍
方法执行数据的时空隧道,记录下指定方法每次调用的入参和返回信息,并能对这些不同的时间下调用进行观测。
记录指定方法的每次调用环境现场:
tt -t class method
列出所有的调用记录:
tt -l
查看调用的信息:
tt -i index
重新发起一次调用
tt -i index -p
使用通道内的引用调用一次
tt -i index -w 'target.method(param)'
获取Spring Context
Spring MVC是基于MVC设计模式的开发框架,是Spring框架中用于WEB开发的一个模块,这个模块的核心是DispatcherServlet,可以将前端的请求分发到各个接口进行业务处理。DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler。解析到对应的Handler后,开始由HandlerAdapter适配器处理。HandlerAdapter会根据Handler来调用真正的处理器开处理请求,并处理相应的业务逻辑。
HandlerAdapter是一个接口,真正实现的是RequestMappingHandlerAdapter,它其中有一个invokeHandlerMethod方法,用于执行目标的HandlerMethod,然后返回一个ModelAndView。每次web请求都会进入这个方法。
而RequestMappingHandlerAdapter继承了ApplicationObjectSupport,我们可以通过getApplicationContext获取到spring context。
结合上面的只是通过和arthas的tt命令结合,我们理论上可以随时调用所有的业务方法。操作如下:
- 执行
tt命令来记录RequestMappingHandlerAdapter invokeHandlerMethod的请求
tt -t org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod
- 通过记录的信息,调用spring context里面保存的对象的方法
`tt -i 1000 -w 'target.getApplicationContext().getBean("helloWorldService").getHelloMessage()'`
注意事项
-
- ThreadLocal 信息丢失 很多框架偷偷的将一些环境变量信息塞到了发起调用线程的 ThreadLocal 中,由于调用线程发生了变化,这些 ThreadLocal 线程信息无法通过 Arthas 保存,所以这些信息将会丢失。 一些常见的 CASE 比如:鹰眼的 TraceId 等。
- 引用的对象 需要强调的是,
tt命令是将当前环境的对象引用保存起来,但仅仅也只能保存一个引用而已。如果方法内部对入参进行了变更,或者返回的对象经过了后续的处理,那么在tt查看的时候将无法看到当时最准确的值。这也是为什么watch命令存在的意义。