5.1 前端控制器 DispatcherServlet

继承结构:
5. MVC源码剖析 - 图1

  1. 前端请求进来,会执行FrameworkServlet的doGet/doPost方法,而doGet/doPost方法都会执行processRequest(request,response)方法,processRequest()主要做的事情有:

    • 获取到上一个请求保存的LocaleContext,建立新的LocaleContext
    • 获取到上一个请求保存的RequestAttributes,建立新的RequestAttributes
    • 调用抽象方法doService(),此方法由继承该类的DispatcherServlet类来实现

      1. protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
      2. throws ServletException, IOException {
      3. long startTime = System.currentTimeMillis();
      4. Throwable failureCause = null;
      5. // 获取到上一个请求保存的LocaleContext
      6. LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
      7. // 建立新的LocaleContext
      8. LocaleContext localeContext = buildLocaleContext(request);
      9. // 获取到上一个请求保存的RequestAttributes
      10. RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
      11. // 建立新的RequestAttributes
      12. ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
      13. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
      14. asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
      15. // 新的RequestAttributes绑定到LocalThread
      16. initContextHolders(request, localeContext, requestAttributes);
      17. try {
      18. doService(request, response);
      19. }
      20. catch (ServletException | IOException ex) {
      21. failureCause = ex;
      22. throw ex;
      23. }
      24. catch (Throwable ex) {
      25. failureCause = ex;
      26. throw new NestedServletException("Request processing failed", ex);
      27. }
      28. finally {
      29. resetContextHolders(request, previousLocaleContext, previousAttributes);
      30. if (requestAttributes != null) {
      31. requestAttributes.requestCompleted();
      32. }
      33. logResult(request, response, failureCause, asyncManager);
      34. publishRequestHandledEvent(request, response, startTime, failureCause);
      35. }
      36. }
  2. DisapatcherServlet类的doService方法主要做的事情:

    • 获取请求域中的属性名存起来做个副本
    • 往request设置一些属性值使框架对象可用于处理程序和视图对象
    • flashMapManager管理重定向参数携带
    • 执行doDispatcher()方法

      1. @Override
      2. protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
      3. logRequest(request);
      4. // Keep a snapshot of the request attributes in case of an include,
      5. // to be able to restore the original attributes after the include.
      6. Map<String, Object> attributesSnapshot = null;
      7. if (WebUtils.isIncludeRequest(request)) {
      8. attributesSnapshot = new HashMap<>();
      9. // 获取请求域中的属性名存起来做个副本
      10. Enumeration<?> attrNames = request.getAttributeNames();
      11. while (attrNames.hasMoreElements()) {
      12. String attrName = (String) attrNames.nextElement();
      13. if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
      14. attributesSnapshot.put(attrName, request.getAttribute(attrName));
      15. }
      16. }
      17. }
      18. // 往request设置一些属性值使框架对象可用于处理程序和视图对象
      19. request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
      20. request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
      21. request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
      22. request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
      23. // flashMapManager管理重定向参数携带
      24. if (this.flashMapManager != null) {
      25. FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
      26. if (inputFlashMap != null) {
      27. request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
      28. }
      29. request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
      30. request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
      31. }
      32. try {
      33. doDispatch(request, response);
      34. }
      35. finally {
      36. if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
      37. // Restore the original attribute snapshot, in case of an include.
      38. if (attributesSnapshot != null) {
      39. restoreAttributesAfterInclude(request, attributesSnapshot);
      40. }
      41. }
      42. }
      43. }

      5.2 核心方法doDisapatcher()分析

      该方法是SpringMVC的核心方法,具体做的事情如下:

      • 1. 检查是否文件上传的请求
      • 2. 取得当前请求的Controller,也称为Handler,即处理器。这里并不是直接返回Controller,而是返 回HandlerExecutionChain请求处理链对象,该对象封装了Handler和Interceptor。如果handler为空则返回404。
      • 3 .获取处理请求的处理器适配器HandlerAdapter,处理last-modified请求头。
      • 4. 实际处理器处理请求,返回结果视图对象ModelAndView,结果视图对象处理
      • 5. 最终会调用HandlerInterceptor的afterCompletion方法 ```java 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. // 1.检查是否文件上传的请求
      2. processedRequest = checkMultipart(request);
      3. multipartRequestParsed = (processedRequest != request);
      4. // Determine handler for the current request.
      5. /**
      6. * 2.取得当前请求的Controller,也称为Handler,即处理器
      7. * 这里并不是直接返回Controller,而是返回HandlerExecutionChain请求处理链对象
      8. * 该对象封装了Handler和Interceptor
      9. */
      10. mappedHandler = getHandler(processedRequest);
      11. if (mappedHandler == null) {
      12. // 如果handler为空则返回404
      13. noHandlerFound(processedRequest, response);
      14. return;
      15. }
      16. // Determine handler adapter for the current request.
      17. // 3.获取处理请求的处理器适配器HandlerAdapter
      18. HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
      19. // Process last-modified header, if supported by the handler.
      20. // 处理last-modified请求头
      21. String method = request.getMethod();
      22. boolean isGet = "GET".equals(method);
      23. if (isGet || "HEAD".equals(method)) {
      24. long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
      25. if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
      26. return;
      27. }
      28. }
      29. if (!mappedHandler.applyPreHandle(processedRequest, response)) {
      30. return;
      31. }
      32. // Actually invoke the handler.
      33. // 4. 实际处理器处理请求,返回结果视图对象ModelAndView
      34. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
      35. if (asyncManager.isConcurrentHandlingStarted()) {
      36. return;
      37. }
      38. // 结果视图对象处理
      39. applyDefaultViewName(processedRequest, mv);
      40. mappedHandler.applyPostHandle(processedRequest, response, mv);

      } catch (Exception ex) {

      1. dispatchException = ex;

      } catch (Throwable err) {

      1. // As of 4.3, we're processing Errors thrown from handler methods as well,
      2. // making them available for @ExceptionHandler methods and other scenarios.
      3. dispatchException = new NestedServletException("Handler dispatch failed", err);

      } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { // 最终会调用HandlerInterceptor的afterCompletion方法 triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } catch (Throwable err) { triggerAfterCompletion(processedRequest, response, mappedHandler,

      1. new NestedServletException("Handler processing failed", err));

      } finally { if (asyncManager.isConcurrentHandlingStarted()) {

      1. // Instead of postHandle and afterCompletion
      2. if (mappedHandler != null) {
      3. mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
      4. }

      } else {

      1. // Clean up any resources used by a multipart request.
      2. if (multipartRequestParsed) {
      3. cleanupMultipart(processedRequest);
      4. }

      } } } ```

      5.3 SpringMVC的核心步骤

  3. 调⽤getHandler()获取到能够处理当前请求的执⾏链 HandlerExecutionChain(Handler+拦截器)

  4. 调⽤getHandlerAdapter();获取能够执⾏1)中Handler的适配器
  5. 适配器调⽤Handler执⾏ha.handle(总会返回⼀个ModelAndView对象)
  6. 调⽤processDispatchResult()⽅法完成视图渲染跳转

    5.3.1 getHandler方法分析

    1. @Nullable
    2. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    3. // 遍历handlerMappings,里面有两个HandlerMapping的实现类
    4. // 分别是BeanNameUrlHandlerMapping和RequestMappingHandlerMapping
    5. if (this.handlerMappings != null) {
    6. for (HandlerMapping mapping : this.handlerMappings) {
    7. // 容器初始化的时候通过扫描注解,配置了url和handler的关系
    8. HandlerExecutionChain handler = mapping.getHandler(request);
    9. if (handler != null) {
    10. // 返回的HandlerExecutionChain包含了Handler和Interceptor信息
    11. return handler;
    12. }
    13. }
    14. }
    15. return null;
    16. }

    5.3.2 getHandlerAdapter方法分析

    1. // 通过Handler匹配到支持的Adapter适配器
    2. protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
    3. if (this.handlerAdapters != null) {
    4. /**
    5. * HandlerAdapter的三个实现类 判断支持那个然后返回
    6. * 1.HttpRequestHandlerAdapter
    7. * 2.SimpleControllerHandlerAdapter
    8. * 3.RequestMappingHandlerAdapter
    9. */
    10. for (HandlerAdapter adapter : this.handlerAdapters) {
    11. if (adapter.supports(handler)) {
    12. return adapter;
    13. }
    14. }
    15. }
    16. throw new ServletException("No adapter for handler [" + handler +
    17. "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
    18. }

    5.3.3 适配器调⽤Handler执⾏ha.handle()方法

  7. mav.invokeHandlerMethod(request,response,handlerMethod)

    • 对handlerMethod进行参数等的适配处理,并调用目标handler
  8. 对请求参数进行处理,调用目标HanderMethod,并且将返回值封装成MethodAndView对象
  9. 对目标handler的参数进行处理,并且调用目标handler
  10. 将request中参数转换成当前handler的参数形式
  11. doInvole()方法主要结合处理后的参数,使用反射对目标方法进行调用

    5.3.4 processDispatchResult()完成视图渲染跳转

    ```java private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
    1. @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
    2. @Nullable Exception exception) throws Exception {
    // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) {
    1. // 是否处理返回渲染的视图
    2. render(mv, request, response);
    3. if (errorView) {
    4. WebUtils.clearErrorRequestAttributes(request);
    5. }
    }

}

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) { View view; String viewName = mv.getViewName(); if (viewName != null) { // We need to resolve the view name. // 解析封装视图 view = resolveViewName(viewName, mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException(“Could not resolve view with name ‘“ + mv.getViewName() + “‘ in servlet with name ‘“ + getServletName() + “‘“); } } }

protected View resolveViewName(String viewName, @Nullable Map model, Locale locale, HttpServletRequest request) throws Exception { // 视图解析器解析视图对象 if (this.viewResolvers != null) { for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } } return null; }

  1. ```java
  2. // 在解析出View视图对象的过程中会判断是否重定向、是否转发等,不同的情况封装的是不同的
  3. // View实现
  4. @Override
  5. protected View createView(String viewName, Locale locale) throws Exception {
  6. // If this resolver is not supposed to handle the given view,
  7. // return null to pass on to the next resolver in the chain.
  8. if (!canHandle(viewName, locale)) {
  9. return null;
  10. }
  11. // Check for special "redirect:" prefix.
  12. if (viewName.startsWith(REDIRECT_URL_PREFIX)) {
  13. String redirectUrl = viewName.substring(REDIRECT_URL_PREFIX.length());
  14. RedirectView view = new RedirectView(redirectUrl,
  15. isRedirectContextRelative(), isRedirectHttp10Compatible());
  16. String[] hosts = getRedirectHosts();
  17. if (hosts != null) {
  18. view.setHosts(hosts);
  19. }
  20. return applyLifecycleMethods(REDIRECT_URL_PREFIX, view);
  21. }
  22. // Check for special "forward:" prefix.
  23. if (viewName.startsWith(FORWARD_URL_PREFIX)) {
  24. String forwardUrl = viewName.substring(FORWARD_URL_PREFIX.length());
  25. InternalResourceView view = new InternalResourceView(forwardUrl);
  26. return applyLifecycleMethods(FORWARD_URL_PREFIX, view);
  27. }
  28. // Else fall back to superclass implementation: calling loadView.
  29. return super.createView(viewName, locale);
  30. }
  1. @Override
  2. public void render(@Nullable Map<String, ?> model, HttpServletRequest request,
  3. HttpServletResponse response) throws Exception {
  4. if (logger.isDebugEnabled()) {
  5. logger.debug("View " + formatViewName() +
  6. ", model " + (model != null ? model : Collections.emptyMap()) +
  7. (this.staticAttributes.isEmpty() ? "" : ", static attributes " + this.staticAttributes));
  8. }
  9. Map<String, Object> mergedModel = createMergedOutputModel(model, request, response);
  10. prepareResponse(request, response);
  11. // 把modelMap中的数据暴露到request请求域中
  12. // 这也是后台model.add后视图可以从请求域中取出的原因
  13. renderMergedOutputModel(mergedModel, getRequestToExpose(request), response);
  14. }

5.4 MVC九大组件分析

  1. MVC的九大组件在DispatcherServlet类中都有定义。 ```java /* MultipartResolver used by this servlet. / // 多部件解析器 @Nullable private MultipartResolver multipartResolver;

/* LocaleResolver used by this servlet. / // 区域化 国际化解析器 @Nullable private LocaleResolver localeResolver;

/* ThemeResolver used by this servlet. / // 主题解析器 @Nullable private ThemeResolver themeResolver;

/* List of HandlerMappings used by this servlet. / // 处理器映射器组件 @Nullable private List handlerMappings;

/* List of HandlerAdapters used by this servlet. / // 处理器适配器组件 @Nullable private List handlerAdapters;

/* List of HandlerExceptionResolvers used by this servlet. / // 异常解析器组件 @Nullable private List handlerExceptionResolvers;

/* RequestToViewNameTranslator used by this servlet. / // 默认视图名转换器组件 @Nullable private RequestToViewNameTranslator viewNameTranslator;

/* FlashMapManager used by this servlet. / // flash属性管理组件 重定向属性 @Nullable private FlashMapManager flashMapManager;

/* List of ViewResolvers used by this servlet. / // 视图解析器 @Nullable private List viewResolvers;

  1. 2. 九⼤组件都是定义了接⼝,接⼝其实就是定义了该组件的规范,⽐如ViewResolverHandlerAdapter等都是接⼝
  2. 3. 九大组件初始化入口
  3. ```java
  4. @Override
  5. protected void onRefresh(ApplicationContext context) {
  6. // 初始化策略
  7. initStrategies(context);
  8. }
  9. protected void initStrategies(ApplicationContext context) {
  10. // 初始化多文件上传组件
  11. initMultipartResolver(context);
  12. // 初始化本地语言环境
  13. initLocaleResolver(context);
  14. // 初始化主题模板处理器
  15. initThemeResolver(context);
  16. // 初始化处理器映射器
  17. initHandlerMappings(context);
  18. // 初始化处理器适配器
  19. initHandlerAdapters(context);
  20. // 初始化异常拦截器
  21. initHandlerExceptionResolvers(context);
  22. // 初始化视图预处理器
  23. initRequestToViewNameTranslator(context);
  24. // 初始化视图转换器
  25. initViewResolvers(context);
  26. // 初始化FlashMap管理器
  27. initFlashMapManager(context);
  28. }
  1. 解析initHandlerMappings:如果按照类型和按照固定id从ioc容器中找不到对应组件,则会按照默认策略进⾏注册初始化,默认策略在DispatcherServlet.properties⽂件中配置

    1. private void initHandlerMappings(ApplicationContext context) {
    2. this.handlerMappings = null;
    3. if (this.detectAllHandlerMappings) {
    4. // 按照HandlerMapping.class类型去ioc容器中找到所有的HandlerMapping
    5. Map<String, HandlerMapping> matchingBeans =
    6. BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
    7. if (!matchingBeans.isEmpty()) {
    8. this.handlerMappings = new ArrayList<>(matchingBeans.values());
    9. // We keep HandlerMappings in sorted order.
    10. AnnotationAwareOrderComparator.sort(this.handlerMappings);
    11. }
    12. }
    13. else {
    14. try {
    15. // 否则在ioc中按照固定名称id(handlerMapping)去查找
    16. HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
    17. this.handlerMappings = Collections.singletonList(hm);
    18. }
    19. catch (NoSuchBeanDefinitionException ex) {
    20. // Ignore, we'll add a default HandlerMapping later.
    21. }
    22. }
    23. // 最后还为控则按照默认策略生成(按照默认方式实例化生成HandlerMapping)
    24. if (this.handlerMappings == null) {
    25. this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
    26. if (logger.isTraceEnabled()) {
    27. logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
    28. "': using default strategies from DispatcherServlet.properties");
    29. }
    30. }
    31. }