背景

Arthas是阿里巴巴開源的Java診斷利器,深受開發者喜愛。

  • https://github.com/alibaba/arthas

之前分享了 Arthas實踐--快速排查Spring Boot應用404/401問題我們可以快速定位一個請求是被哪些 Filter 攔截的,或者請求最終是由哪些 Servlet 處理的。

但有時,我們想知道一個請求是被哪個Spring MVC Controller處理的。如果翻代碼的話,會比較難找,並且不一定準確。

通過Arthas可以精確定位是哪個 Controller 處理請求。

Demo

還是以這個demo爲例:

  • https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-404-401

啓動之後,訪問: http://localhost:8080/user/1 ,會返回一個user對象。那麼這個請求是被哪個 Controller 處理的呢?

trace定位DispatcherServlet

我們先試下跟蹤 Servlet

trace javax.servlet.Servlet *

從trace的結果可以看出來,請求最終是被 DispatcherServlet#doDispatch() 處理了,但是沒有辦法知道是哪個 Controller 處理。

---[27.453122ms] org.springframework.web.servlet.DispatcherServlet:doDispatch()
    +---[0.005822ms] org.springframework.web.context.request.async.WebAsyncUtils:getAsyncManager() #929
    +---[0.107365ms] org.springframework.web.servlet.DispatcherServlet:checkMultipart() #936
    |   `---[0.062451ms] org.springframework.web.servlet.DispatcherServlet:checkMultipart()
    |       `---[0.016924ms] org.springframework.web.multipart.MultipartResolver:isMultipart() #1093
    +---[2.103935ms] org.springframework.web.servlet.DispatcherServlet:getHandler() #940
    |   `---[2.036042ms] org.springframework.web.servlet.DispatcherServlet:getHandler()

watch定位handler

trace結果裏把調用的行號打印出來了,我們可以直接在IDE裏查看代碼(也可以用jad命令反編譯):

// org.springframework.web.servlet.DispatcherServlet
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;

        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);

        try {
            ModelAndView mv = null;
            Exception dispatchException = null;

            try {
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

                // Determine handler for the current request.
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
  • 仔細看代碼,可以發現 mappedHandler = getHandler(processedRequest); 得到了處理請求的handler

那麼下面用 watch 命令來獲取 getHandler 函數的返回結果。

watch 之後,再次訪問 http://localhost:8080/user/1

$ watch org.springframework.web.servlet.DispatcherServlet getHandler returnObj
Press Q or Ctrl+C to abort.
Affect(class-cnt:1 , method-cnt:1) cost in 332 ms.
ts=2019-06-04 11:38:06; [cost=2.75218ms] result=@HandlerExecutionChain[
    logger=@SLF4JLocationAwareLog[org.apache.commons.logging.impl.SLF4JLocationAwareLog@665c08a],
    handler=@HandlerMethod[public com.example.demo.arthas.user.User com.example.demo.arthas.user.UserController.findUserById(java.lang.Integer)],
    interceptors=null,
    interceptorList=@ArrayList[isEmpty=false;size=2],
    interceptorIndex=@Integer[-1],
]

可以看到處理請求的handler是 om.example.demo.arthas.user.UserController.findUserById

總結

  • Spring MVC的請求是在 DispatcherServlet 分發,查找到對應的 mappedHandler 來處理

  • 使用Arthas時,靈活結合代碼,可以快速精確定位問題

鏈接

  • https://github.com/alibaba/arthas

  • https://alibaba.github.io/arthas/watch.html

  • https://alibaba.github.io/arthas/trace.html

既然談到了Spring MVC,那麼就要談微服務,談到微服務,自然要談下最近收到的新書

本次聯合 【機械工業出版社華章公司】 贈送2本當當新書榜 No.1 的好書《微服務架構設計模式》。

微服務架構設計模式

作者 :[美]克里斯·理查森(Chris Richardson)著

譯者: 喻勇譯

推薦語:

世界十大軟件架構師之一、微服務架構先驅 Chris Richardson 親筆撰寫,微服務實用落地指南。

涵蓋 44 個架構設計模式,系統解決服務拆分、事務管理、查詢和跨服務通信等難題

易寶支付 CTO 陳斌、 PolarisTech 聯合創始人蔡書、才雲科技 CEO 張鑫等多位專家鼎力推薦。

本次活動從讚賞區隨機抽取2名幸運讀者,各贈送《微服務架構設計模式》1本。截止日期2019-6-10日。

未獲獎的讀者也可以長按識別二維碼購買

點擊“閱讀原文”,瞭解更多微服務架構好書

相關文章