首先: 容器启动时候,会在DispatcherServlet的handlerMappings中添加beanName与类对应的map映射, 以便于后续getHandler时候用{GET /test/t1}来取得对应请求的方法 。

map映射
简要流程:
- 所有请求发来,到DispatcherServlet收到请求
- 调用doDispatch()方法进行处理
- getHandler():根据请求地址和mappingRegistry(上面有提到,可查找)找到能处理这个请求的目标处理类(处理器<控制器>)
- getHandlerAdapter():根据当前处理器类(控制器)获取能处理这个处理器方法的适配器;
- 使用获得的适配器ha(AnnotationMethodHandlerAdapter)执行目标方法
- 适配器调用目标方法后,都会返回ModelAndView对象mv = ha.handle(processedRequest, response, mappedHandler.getHandler())
- 根据ModelAndView信息转发到具体页面,并可以在请求域中取得对象的Model数据
前端发送请求后,在DispatcherServlet类中, 底层调用doDispatch()方法 。
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 { //1、检查是否为文件上传请求 processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // Determine handler for the current request. //2、决定哪个控制器处理这个请求,下面有代码解释 mappedHandler = getHandler(processedRequest); //取出后会发现值为:public java.lang.String com.zhangxujie.controller.TestController.t1() //3、如果未找到处理这个请求的控制器,则异常等处理 if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. //4、知道请求的类后,要拿到响应的适配器去处理请求,而不是用原始类处理(拿到反射工具) HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); //取得了对应的注解适配器,目的可能为了方便Spring的AOP操作 // Process last-modified header, if supported by the handler. // 获取请求方式,当前为GET String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet "HEAD".equals(method)) {//如果是GET请求,如何如何,加缓存等等 long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } //5、适配器执行目标方法 // Actually invoke the handler,处理器方法被真正调用 //控制器(Controller)=处理器(handler) mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); //通过适配器执行目标方法,返回ModelAndView对象(本段代码结束后图一) //代码内部在7、Spring MVC 部分源码分析(2) //无论目标方法如何写,最终适配器都要执行后返回ModelAndView对象 if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } //6、根据方法最终执行后封装的ModelAndView转发到对应页面,而且ModelAndView中的数据可以从请求域中获取 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", err)); } finally { if (asyncManager.isConcurrentHandlingStarted()) { // Instead of postHandle and afterCompletion if (mappedHandler != null) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else { // Clean up any resources used by a multipart request. if (multipartRequestParsed) { cleanupMultipart(processedRequest); } } } }
其中,方法开始时调用getHandler()方法,是用来确定哪个控制器来处理这个请求,同时获得目标处理器执行链(包括拦截器)
getHandler细节
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { for (HandlerMapping mapping : this.handlerMappings) {//遍历Handlermap,以取得对应控制器 //此处进入下面的方法getHandlerInternal() HandlerExecutionChain handler = mapping.getHandler(request); //执行到这里,已经获得了执行控制器TestController.t1() if (handler != null) { return handler; } } } return null; } ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// /** * Look up a handler method for the given request. */ @Override protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { String lookupPath = getUrlPathHelper().getLookupPathForRequest(request); //mappingRegistry存着所有控制器请求url和对应类方法,(本段代码结束后图一),下面要查找bean,所以上读锁 this.mappingRegistry.acquireReadLock(); try { //通过请求url找到最符合的请求方法,当前为TestController.t1() HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } finally { this.mappingRegistry.releaseReadLock(); } }

图一
Author: Leisurelybear
Link: https://blog.lebear.top/2020/03/14/142/
Copyright: Copyright © 2019-2022 LeisurelyBear All rights reserved.