使用spring web mvc 时[spring boot 包含了 webmvc] 基本上会使用到
1. servlet 本身的 filter [不属于 mvc 层]
2. mvc 的 intercepter pre 和 post ,complete 调用, 含url路径筛选匹配
3. controller 执行,含 url 路径筛选匹配
4. 将返回的model的数据组装到对应的 View 中
3. mvc 的异常处理. @ExceptionHandler 或者全局的 @ControllerAdvice
要把这些逻辑组装在一起,还有概念
1. 核心流程类DispatcherServlet[是否是静态文件,负责为 url 找到对应的 controller,负责寻找和执行 intercepter,异常判断和处理]
2. ExceptionHandlerExceptionResolver exeptionHandler 的容器, 负责寻找匹配和执行异常处理逻辑.
见附录的doResolveHandlerMethodException. 默认的处理类?
3.
附录:
- error():37, CheckCommandController {com..platform.consistent.checker.controller} Controller的@ExceptionHandler方法
- invoke0():-1, NativeMethodAccessorImpl {sun.reflect}
- invoke():62, NativeMethodAccessorImpl {sun.reflect}
- invoke():43, DelegatingMethodAccessorImpl {sun.reflect}
- invoke():498, Method {java.lang.reflect}
- doInvoke():220, InvocableHandlerMethod {org.springframework.web.method.support}
- invokeForRequest():134, InvocableHandlerMethod {org.springframework.web.method.support}
- invokeAndHandle():116, ServletInvocableHandlerMethod {org.springframework.web.servlet.mvc.method.annotation}
- doResolveHandlerMethodException():381, ExceptionHandlerExceptionResolver {org.springframework.web.servlet.mvc.method.annotation}
Resolver容器找到对应的 handler 和 exception 的 ServletInvocableHandlerMethod,先exceptionHandlerCache,再从exceptionHandlerAdviceCache中获取. 代码如下
ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception); /** * Find an {@code @ExceptionHandler} method for the given exception. The default * implementation searches methods in the class hierarchy of the controller first * and if not found, it continues searching for additional {@code @ExceptionHandler} * methods assuming some {@linkplain ControllerAdvice @ControllerAdvice} * Spring-managed beans were detected. * @param handlerMethod the method where the exception was raised (may be {@code null}) * @param exception the raised exception * @return a method to handle the exception, or {@code null} */ protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) { Class<?> handlerType = (handlerMethod != null ? handlerMethod.getBeanType() : null); if (handlerMethod != null) { ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(handlerType); if (resolver == null) { resolver = new ExceptionHandlerMethodResolver(handlerType); this.exceptionHandlerCache.put(handlerType, resolver); } Method method = resolver.resolveMethod(exception); if (method != null) { return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method); } } for (Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry : this.exceptionHandlerAdviceCache.entrySet()) { if (entry.getKey().isApplicableToBeanType(handlerType)) { ExceptionHandlerMethodResolver resolver = entry.getValue(); Method method = resolver.resolveMethod(exception); if (method != null) { return new ServletInvocableHandlerMethod(entry.getKey().resolveBean(), method); } } } return null; }
- doResolveException():59, AbstractHandlerMethodExceptionResolver {org.springframework.web.servlet.handler}
- resolveException():136, AbstractHandlerExceptionResolver {org.springframework.web.servlet.handler}
- resolveException():74, HandlerExceptionResolverComposite {org.springframework.web.servlet.handler}
- processHandlerException():1193, DispatcherServlet {org.springframework.web.servlet}
- processDispatchResult():1030, DispatcherServlet {org.springframework.web.servlet}
- doDispatch():980, DispatcherServlet {org.springframework.web.servlet}
流程组装处,时序图最核心代码.
/** * 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 || mappedHandler.getHandler() == 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 (logger.isDebugEnabled()) { logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) { return; } } if (!mappedHandler.applyPreHandle(processedRequest, response)) { // phil 注: 先调用拦截器的 pre return; } // Actually invoke the handler. mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return; } applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); // phil 注: 后调用拦截器的 post } 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); // phil 注:1. exception 逻辑. exception 逻辑见上面堆栈注释.2.处理 view 的处理 3. mappedHandler.triggerAfterCompletion(request, response, null); } 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); } } } }
/** * Handle the result of handler selection and handler invocation, which is * either a ModelAndView or an Exception to be resolved to a ModelAndView. */ private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, HandlerExecutionChain mappedHandler, ModelAndView mv, Exception exception) throws Exception { boolean errorView = false; if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isDebugEnabled()) { logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() + "': assuming HandlerAdapter completed request handling"); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { mappedHandler.triggerAfterCompletion(request, response, null); // phil注: intercepter 的 complete } }
- doService():897, DispatcherServlet {org.springframework.web.servlet}