Spring MVC源码阅读笔记
刷了一遍spring mvc源码,记录一下,写的可能有点乱。
DispatcherServlet的核心方法为doDispatch,上图中的流程基本都在doDispatch中完成,下面贴上源码
/** * Process the actual dispatching to the handler. * <p>The handler will be obtained by applying the servlet's HandlerMappings in order. * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters * to find the first that supports the handler class. * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers * themselves to decide which methods are acceptable. * @param request current HTTP request * @param response current HTTP response * @throws Exception in case of any kind of processing failure */ 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) { noHandlerFound(processedRequest, response); return; } // Determine handler adapter for the current request. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // Process last-modified header, if supported by the handler. String method = request.getMethod(); boolean isGet = "GET".equals(method); if (isGet || "HEAD".equals(method)) { long lastModified = ha.getLastModified(request, mappedHandler.getHandler()); if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); 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); } 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); } } } }
然后分析一下几个关键的节点
1.获取handler
HandlerExecutionChain mappedHandler,这个为实际调度的对象,他的内部包含一个handler和一系列的拦截器,下面为官方注释
简单翻译一下,处理程序执行链,由handler和HandlerInterceptor组成。由HandlerMapping.getHandler方法返回这个对象。下面为类图
然后看一下如何获取HandlerExecutionChain mappedHandler这个对象
看代码只要匹配到第一个就返回了,然后看一下这个HandlerMapping.getHanlder方法
翻译一下注释
返回此请求的处理程序和任何拦截器。可以根据请求URL、会话状态或实现类选择的任何因素进行选择。 返回的HandlerExecutionChain包含一个处理程序对象,而不是标记接口,因此处理程序不受任何约束。例如,可以编写HandlerAdapter来允许使用另一个框架的ni处理程序对象。如果没有找到匹配,则返回null。这不是一个错误。DispatcherServlet将查询所有已注册的HandlerMapping bean以查找匹配项,并且只有在没有找到处理程序时才判断是否存在错误。
找一个比较常见的实现类RequestMappingHandlerMapping
先说结果RequestMappingHandlerMapping的getHanlder最终实现方式是通过@RequestMapping中的参数去匹配对应的方法,然后组装成Handler并加上对应的拦截器生成HandlerExecutionChain对象返回
RequestMappingHandlerMapping继承关系
在RequestMappingHandlerMapping中并没有找到getHanlder这个方法,最后在AbstractHandlerMapping这个类中找到了实现,红框是重点关注的部分
(1)getHandlerInternal,这个主要是根据@RequestMapping中的参数匹配查找对应的handler,RequestMappingHandlerMapping的具体实现在父类AbstractHandlerMethodMapping
(2)getHandlerExecutionChain,这个方法是根据@RequestMapping中的参数匹配对应的拦截器然后和handler组装返回一个HandlerExecutionChain
小结一下,最常见的@Controller和@RequestMapping注册在RequestMappingHandlerMapping中,@RequestMapping中的参数进行匹配
其他的HandlerMapping还有很多,比如WebSocketHandlerMapping,WelcomePageHandlerMapping等,此处不展开
2.获取对应的HandlerAdapter
实现方法为getHandlerAdapter
关键代码为HandlerAdapter的supports,这是一个接口,所以找一个实现类,以RequestMappingHandlerAdapter为例,他的实现在父类AbstractHandlerMethodAdapter中,主要判断这个类是否是HandlerMethod类型
其他的实现类还有SimpleControllerHandlerAdapter(处理继承Controller接口的类),SimpleServletHandlerAdapter(处理Servlet类型的类)
3.获取到mappedHandler和handlerAdapter后,可以执行handlerAdapter的handle方法了,以RequestMappingHandlerAdapter为例
在执行真正的handler之前需要先执行mappedHandler中的applyPreHandle方法,这个主要是调用mappedHandler中对应拦截器的preHandle方法。
之后通过handlerAdapter执行mappedHandler中真正的handler
RequestMappingHandlerAdapter的handle方法有点绕,下面一点一点找
AbstractHandlerMethodAdapter.handle
AbstractHandlerMethodAdapter.handleInternal是一个抽象方法,在RequestMappingHandlerAdapter中实现
然后看RequestMappingHandlerAdapter.invokeHandlerMethod(代码有点长,一张图截不下)
/** * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView} * if view resolution is required. * @since 4.2 * @see #createInvocableHandlerMethod(HandlerMethod) */ @Nullable protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); try { WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); if (this.argumentResolvers != null) { invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } if (this.returnValueHandlers != null) { invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); } invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); modelFactory.initModel(webRequest, mavContainer, invocableMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response); asyncWebRequest.setTimeout(this.asyncRequestTimeout); WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); asyncManager.setTaskExecutor(this.taskExecutor); asyncManager.setAsyncWebRequest(asyncWebRequest); asyncManager.registerCallableInterceptors(this.callableInterceptors); asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors); if (asyncManager.hasConcurrentResult()) { Object result = asyncManager.getConcurrentResult(); mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0]; asyncManager.clearConcurrentResult(); LogFormatUtils.traceDebug(logger, traceOn -> { String formatted = LogFormatUtils.formatValue(result, !traceOn); return "Resume with async result [" + formatted + "]"; }); invocableMethod = invocableMethod.wrapConcurrentResult(result); }
invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } }
进入ServletInvocableHandlerMethod.invokeAndHandle
进入最关键的代码InvocableHandlerMethod.invokeForRequest(ServletInvocableHandlerMethod是InvocableHandlerMethod的子类)
先翻译一下注释
在给定请求的上下文中解析其参数值后调用该方法。 参数值通常通过HandlerMethodArgumentResolvers解析器解析。然而,providedArgs参数可以提供直接使用的参数值,即不需要参数解析。提供的参数值示例包括WebDataBinder、SessionStatus或抛出的异常实例。提供的参数值在参数解析器之前检查。 委托给getMethodArgumentValues并使用解析后的参数调用doInvoke。
/** * Invoke the method after resolving its argument values in the context of the given request. * <p>Argument values are commonly resolved through * {@link HandlerMethodArgumentResolver HandlerMethodArgumentResolvers}. * The {@code providedArgs} parameter however may supply argument values to be used directly, * i.e. without argument resolution. Examples of provided argument values include a * {@link WebDataBinder}, a {@link SessionStatus}, or a thrown exception instance. * Provided argument values are checked before argument resolvers. * <p>Delegates to {@link #getMethodArgumentValues} and calls {@link #doInvoke} with the * resolved arguments. * @param request the current request * @param mavContainer the ModelAndViewContainer for this request * @param providedArgs "given" arguments matched by type, not resolved * @return the raw value returned by the invoked method * @throws Exception raised if no suitable argument resolver can be found, * or if the method raised an exception * @see #getMethodArgumentValues * @see #doInvoke */ @Nullable public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs); if (logger.isTraceEnabled()) { logger.trace("Arguments: " + Arrays.toString(args)); } return doInvoke(args); }
InvocableHandlerMethod.getMethodArgumentValues方法,主要作用为获取参数值,参数值通过HandlerMethodArgumentResolver进行解析。
匹配方式可以参考RequestMappingHandlerAdapter.getDefaultArgumentResolvers方法中具体的HandlerMethodArgumentResolver。
这个HandlerMethodArgumentResolver其实也可以自行扩展,可以参考https://www.jianshu.com/p/40606baf49b8
/** * Get the method argument values for the current request, checking the provided * argument values and falling back to the configured argument resolvers. * <p>The resulting array will be passed into {@link #doInvoke}. * @since 5.1.2 */ protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception { MethodParameter[] parameters = getMethodParameters(); if (ObjectUtils.isEmpty(parameters)) { return EMPTY_ARGS; } Object[] args = new Object[parameters.length]; for (int i = 0; i < parameters.length; i++) { MethodParameter parameter = parameters[i]; parameter.initParameterNameDiscovery(this.parameterNameDiscoverer); args[i] = findProvidedArgument(parameter, providedArgs); if (args[i] != null) { continue; } if (!this.resolvers.supportsParameter(parameter)) { throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver")); } try { args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory); } catch (Exception ex) { // Leave stack trace for later, exception may actually be resolved and handled... if (logger.isDebugEnabled()) { String exMsg = ex.getMessage(); if (exMsg != null && !exMsg.contains(parameter.getExecutable().toGenericString())) { logger.debug(formatArgumentError(parameter, exMsg)); } } throw ex; } } return args; }
获取到参数后,可以执行doInvoke方法了,这个比较简单,就是使用反射执行对应的方法
/** * Invoke the handler method with the given argument values. */ @Nullable protected Object doInvoke(Object... args) throws Exception { ReflectionUtils.makeAccessible(getBridgedMethod()); try { return getBridgedMethod().invoke(getBean(), args); } catch (IllegalArgumentException ex) { assertTargetBean(getBridgedMethod(), getBean(), args); String text = (ex.getMessage() != null ? ex.getMessage() : "Illegal argument"); throw new IllegalStateException(formatInvokeError(text, args), ex); } catch (InvocationTargetException ex) { // Unwrap for HandlerExceptionResolvers ... Throwable targetException = ex.getTargetException(); if (targetException instanceof RuntimeException) { throw (RuntimeException) targetException; } else if (targetException instanceof Error) { throw (Error) targetException; } else if (targetException instanceof Exception) { throw (Exception) targetException; } else { throw new IllegalStateException(formatInvokeError("Invocation failure", args), targetException); } }
小结一下RequestMappingHandlerAdapter的handle方法的核心为使用HandlerMethodArgumentResolver处理参数,之后使用反射方式执行controller中的method。
最后总结一下我们最常见的@RequestMapping和@Controller在Spring MVC中的执行过程
从RequestMappingHandlerMapping获取对应的HandlerExecutionChain mappedHandler
然后使用RequestMappingHandlerAdapter.handle 方法处理mappedHandler生成modelAndView
之后交由ViewResoler生成view,最后response根据view进行渲染