Arthas 实践:是哪个 Controller 处理了请求?

2019-06-05 10:47:08 +08:00
 hengyunabc

背景

Arthas 是阿里巴巴开源的 Java 诊断利器,深受开发者喜爱。

之前分享了 Arthas 怎样排查 404/401 的问题: http://hengyunabc.github.io/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;
				}

下面用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

总结

链接

原文地址

2039 次点击
所在节点    Java
1 条回复
fuchaofather
2019-06-05 11:41:39 +08:00
确实好用

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/571031

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX