背景
Arthas 是Alibaba開源的Java診斷工具,深受開發者喜愛。
Arthas提供了非常豐富的關于調用攔截的指令,比如 trace/watch/monitor/tt 。但是很多時候我們在排查問題時,需要更多的線索,并不隻是函數的參數和傳回值。
比如在一個spring應用裡,想擷取到spring context裡的其它bean。如果能随意擷取到spring bean,那就可以“為所欲為”了。
下面介紹如何利用Arthas擷取到spring context。
Demo:
https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-arthas-spring-bootArthas快速開始:
https://alibaba.github.io/arthas/quick-start.html使用tt指令擷取到spring context
Demo是一個spring mvc應用,請求會經過一系列的spring bean處理,那麼我們可以在spring mvc的類裡攔截到一些請求。
啟動Demo:
mvn spring-boot:run
使用Arthas Attach成功之後,執行
tt
指令來記錄
RequestMappingHandlerAdapter#invokeHandlerMethod
的請求
tt -t org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod
然後通路一個網頁:
http://localhost:8080/可以看到Arthas會攔截到這個調用,index是1000,并且列印出:
$ watch com.example.demo.Test * 'params[0]@sss'
$ tt -t org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter invokeHandlerMethod
Press Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 101 ms.
INDEX TIMESTAMP COST(ms IS-RE IS-EX OBJECT CLASS METHOD
) T P
------------------------------------------------------------------------------------------------------------------
1000 2019-01-27 16:31 3.66744 true false 0x4465cf70 RequestMappingHandlerAda invokeHandlerMethod
:54 pter
那麼怎樣擷取到spring context?
可以用
tt
指令的
-i
參數來指定index,并且用
-w
參數來執行ognl表達式來擷取spring context:
$ tt -i 1000 -w 'target.getApplicationContext()'
@AnnotationConfigEmbeddedWebApplicationContext[
reader=@AnnotatedBeanDefinitionReader[org.springframework.context.annotation.AnnotatedBeanDefinitionReader@35dc90ec],
scanner=@ClassPathBeanDefinitionScanner[org.springframework.context.annotation.ClassPathBeanDefinitionScanner@72078a14],
annotatedClasses=null,
basePackages=null,
]
Affect(row-cnt:1) cost in 7 ms.
從spring context裡擷取任意bean
擷取到spring context之後,就可以擷取到任意的bean了,比如擷取到
helloWorldService
,并調用
getHelloMessage()
函數:
$ tt -i 1000 -w 'target.getApplicationContext().getBean("helloWorldService").getHelloMessage()'
@String[Hello World]
Affect(row-cnt:1) cost in 5 ms.
更多的思路
在很多代碼裡都有static函數或者static holder類,順滕摸瓜,可以擷取很多其它的對象。比如在Dubbo裡通過
SpringExtensionFactory
擷取spring context:
$ 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],
]