Arthas實踐:是哪一個Controller處理了請求?

背景

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

以前分享了Arthas怎樣排查 404/401 的問題: http://hengyunabc.github.io/arthas-spring-boot-404-401/java

咱們能夠快速定位一個請求是被哪些Filter攔截的,或者請求最終是由哪些Servlet處理的。git

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

經過Arthas能夠精肯定位是哪一個Controller處理請求。web

Demo

仍是以這個demo爲例: https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-404-401spring

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

trace定位DispatcherServlet

咱們先試下跟蹤Servletbash

trace javax.servlet.Servlet *

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

`---[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命令反編譯):async

// 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時,靈活結合代碼,能夠快速精肯定位問題

連接

公衆號

歡迎關注橫雲斷嶺的專欄,專一Java,Spring Boot,Arthas,Dubbo。

橫雲斷嶺的專欄

相關文章
相關標籤/搜索