Spring MVC请求处理的流程(以下源码中注释了每一步干了那些事情)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 protected void doDispatch (HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null ; boolean multipartRequestParsed = false ; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { try { ModelAndView mv = null ; Object dispatchException = null ; try { processedRequest = this .checkMultipart(request); multipartRequestParsed = processedRequest != request; mappedHandler = this .getHandler(processedRequest); if (mappedHandler == null ) { this .noHandlerFound(processedRequest, response); return ; } HandlerAdapter ha = this .getHandlerAdapter(mappedHandler.getHandler()); 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 ; } mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); if (asyncManager.isConcurrentHandlingStarted()) { return ; } this .applyDefaultViewName(processedRequest, mv); mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception var20) { dispatchException = var20; } catch (Throwable var21) { dispatchException = new NestedServletException("Handler dispatch failed" , var21); } this .processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException); } catch (Exception var22) { this .triggerAfterCompletion(processedRequest, response, mappedHandler, var22); } catch (Throwable var23) { this .triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed" , var23)); } } finally { if (asyncManager.isConcurrentHandlingStarted()) { if (mappedHandler != null ) { mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response); } } else if (multipartRequestParsed) { this .cleanupMultipart(processedRequest); } } }
结合源码详细解析一下上述主要步骤: // 2.如何找到处理当前请求的处理器 mappedHandler = this.getHandler(processedRequest)返回目标方法的执行链(内部还封装了拦截器等信息) handlerMappings:IOC容器启动时创键Controller对象扫描到每个处理器都能处理那些请求,保存在HanlerMaping的handlerMap中,每过来一个请求,拿到该请求对应的HandlerMapping的请求映射信息就行; 下面这段就是根据请求获取请求对应的HandlerMapping映射信息的源码 (目前MVC支持RequestMappingHandlerMapping、 BeanNameUrlHandlerMapping、 RouterFunctionMapping三种)
1 2 3 4 5 6 7 8 9 10 11 12 @Nullable protected HandlerExecutionChain getHandler (HttpServletRequest request) throws Exception { if (this .handlerMappings != null ) { for (HandlerMapping mapping : this .handlerMappings) { HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null ) { return handler; } } } return null ; }
// 3.如何拿到当前处理器所有方法的适配器(相当于反射工具) (目前MVC支持RequestMappingHandlerAdapter、 HandlerFunctionAdapter、 HttpRequestHandlerAdapter、 SimpleControllerHandlerAdapter四种)
1 2 3 4 5 6 7 8 9 10 11 protected HandlerAdapter getHandlerAdapter (Object handler) throws ServletException { if (this .handlerAdapters != null ) { for (HandlerAdapter adapter : this .handlerAdapters) { if (adapter.supports(handler)) { return adapter; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler" ); }
DispatcherServlet中的几种引用类型的属性:Spring MVC的九大组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 @Nullable private MultipartResolver multipartResolver; @Nullable private LocaleResolver localeResolver;@Nullable private ThemeResolver themeResolver;@Nullable private List<HandlerMapping> handlerMappings;@Nullable private List<HandlerAdapter> handlerAdapters;@Nullable private List<HandlerExceptionResolver> handlerExceptionResolvers;@Nullable private RequestToViewNameTranslator viewNameTranslator;@Nullable private FlashMapManager flashMapManager;@Nullable private List<ViewResolver> viewResolvers;
Spring MVC九大组件初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 @Override protected void onRefresh (ApplicationContext context) { initStrategies(context); } protected void initStrategies (ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }
MVC支持Rest风格原理(源码解析)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 public static final String DEFAULT_METHOD_PARAM = "_method" ;private String methodParam = DEFAULT_METHOD_PARAM;@Override protected void doFilterInternal (HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { HttpServletRequest requestToUse = request; if ("POST" .equals(request.getMethod()) && request.getAttribute(WebUtils.ERROR_EXCEPTION_ATTRIBUTE) == null ) { String paramValue = request.getParameter(this .methodParam); if (StringUtils.hasLength(paramValue)) { String method = paramValue.toUpperCase(Locale.ENGLISH); if (ALLOWED_METHODS.contains(method)) { requestToUse = new HttpMethodRequestWrapper(request, method); } } } filterChain.doFilter(requestToUse, response); } private static class HttpMethodRequestWrapper extends HttpServletRequestWrapper { private final String method; public HttpMethodRequestWrapper (HttpServletRequest request, String method) { super (request); this .method = method; } @Override public String getMethod () { return this .method; } } public class HttpServletRequestWrapper extends ServletRequestWrapper implements HttpServletRequest { 、、、 }
从上述源码中可以看到: MVC实现Rest风格的是通过HiddenHttpMethodFilter这个拦截器实现的,在该拦截器的doFilterInternal方法中通过获取到参数中”method”对应的属性值来拿到请求类型,然后调用HttpMethodRequestWrapper构造方法,而HttpMethodRequestWrapper继承了HttpServletRequest可以看出这里其实就是通过传入的request,method两个参数构造了一个request,而method就是我们所传的参数,从而达到对Rest四种请求方式的支持。
@RequestParam(value = “”, required = false, defaultValue = “”) @RequestHeader(value = “”, required = false, defaultValue = “”) @CookieValue(value = “”, required = false)
Spring MVC解决乱码问题 处理字符编码的Filter一定要在其他Filter之前,不然其他Filter已经获取的请求参数,此时再去处理字符编码没有任何意义
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class CharacterEncodingFilter extends OncePerRequestFilter { @Nullable private String encoding; private boolean forceRequestEncoding = false ; private boolean forceResponseEncoding = false ; public boolean isForceResponseEncoding () { return this .forceResponseEncoding; } @Override protected void doFilterInternal ( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String encoding = getEncoding(); if (encoding != null ) { if (isForceRequestEncoding() || request.getCharacterEncoding() == null ) { request.setCharacterEncoding(encoding); } if (isForceResponseEncoding()) { response.setCharacterEncoding(encoding); } } filterChain.doFilter(request, response); } }
Spring MVC如何把数据带给页面 不管是传入Map, Model, MOdelMap,最终都是BindingAwareModelMap在工作,相当于在BindingAwareModelMap中保存的数据都放在请求域中