Spring MVC源码学习

1
2
3
4
5
6
7
8
9
public class DispatcherServlet extends FrameworkServlet {
  private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";

  static {
    // Load default strategy implementations from properties file.
    ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
    defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
  }
}

resources/org/springframework/web/servlet/DispatcherServlet.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,</span>
  org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,</span>
  org.springframework.web.servlet.function.support.RouterFunctionMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,</span>
  org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,</span>
  org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,</span>
  org.springframework.web.servlet.function.support.HandlerFunctionAdapter


org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,</span>
  org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,</span>
  org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

在context成功的refresh过后,onRefresh方法就会被调用,然后它会调用initStrategies 方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
  protected void onRefresh(ApplicationContext context) {
    initStrategies(context);
  }

  // Initialize the strategy objects that this servlet uses.
  protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context);
    initLocaleResolver(context);
    initThemeResolver(context);
    initHandlerMappings(context);
    initHandlerAdapters(context);
    initHandlerExceptionResolvers(context);
    initRequestToViewNameTranslator(context);
    initViewResolvers(context);
    initFlashMapManager(context);
  }

几个关键的初始化方法:initHandlerMappings,initHandlerAdapters,initHandlerExceptionResolvers,initViewResolvers。

initHandlerMappings

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
  private boolean detectAllHandlerMappings = true;
  private List<HandlerMapping> handlerMappings;

  private void initHandlerMappings(ApplicationContext context) {
    this.handlerMappings = null;

    if (this.detectAllHandlerMappings) {
      // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
      Map<String, HandlerMapping> matchingBeans =
          BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
      if (!matchingBeans.isEmpty()) {
        this.handlerMappings = new ArrayList<>(matchingBeans.values());
        // We keep HandlerMappings in sorted order.
        AnnotationAwareOrderComparator.sort(this.handlerMappings);
      }
    }
    else {
      try {
        HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
        this.handlerMappings = Collections.singletonList(hm);
      }
      catch (NoSuchBeanDefinitionException ex) {
        // Ignore, we'll add a default HandlerMapping later.
      }
    }

    // Ensure we have at least one HandlerMapping, by registering
    // a default HandlerMapping if no other mappings are found.
    if (this.handlerMappings == null) {
      this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
      if (logger.isTraceEnabled()) {
        logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
            "': using default strategies from DispatcherServlet.properties");
      }
    }
  }

  protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
    String key = strategyInterface.getName();
    String value = defaultStrategies.getProperty(key);
    if (value != null) {
      String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
      List<T> strategies = new ArrayList<>(classNames.length);
      for (String className : classNames) {
        Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
        Object strategy = createDefaultStrategy(context, clazz);
        strategies.add((T) strategy);
      }
      return strategies;
    } else {
      return new LinkedList<>();
    }
  }

会走到getDefaultStrategies,加载不同的strategy对象。它会用StringUtils工具类把拿到的value根据逗号分开存入到String 数组中,然后遍历这些名字,根据相应的名字加载相应的类,创建相应的对象。

看DispatcherServlet.properties,有 * org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping * org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping * org.springframework.web.servlet.function.support.RouterFunctionMapping

initHandlerAdapters

和initHandlerMappings类似,最后都是根据DispatcherServlet.properties的配置初始化 * org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter * org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter * org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter * org.springframework.web.servlet.function.support.HandlerFunctionAdapter

initHandlerExceptionResolvers

和initHandlerMappings类似,最后都是根据DispatcherServlet.properties的配置初始化 * org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver * org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver * org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

initViewResolvers

和initHandlerMappings类似,最后都是根据DispatcherServlet.properties的配置初始化 * org.springframework.web.servlet.view.InternalResourceViewResolver

处理请求

DispatcherServlet是一个Servlet,它间接继承自HttpServlet,它重写了doService方法。当从客户端发出一个请求时,它会首先执行它的doService方法

doService的工作: * 记日志,调用logRequest(request) * Keep a snapshot of the request attributes in case of an include. Map<String, Object> attributesSnapshot * Make framework objects available to handlers and view objects. `request.setAttribute(key, val) * 调用doDispatch(request, response)

找到当前请求的handler

doDispatch 方法中调用getHandler方法找到相应请求的Handler,返回的是一个HandlerExecutionChain对象。框架把找到的Handler(即我们处理请求的Controller)和一些个拦截器包装到这个对象中。HandlerExecutionChain包含拦截器的逻辑,applyPreHandle, applyPostHandle

1
2
3
4
5
6
7
8
9
10
11
  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;
  }

看org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,其实调用的是AbstractHandlerMapping.getHandler(), 再调用AbstractUrlHandlerMapping.getHandlerInternal(),并调用lookupHandler()

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
public class RequestMappingHandlerMapping extends RequestMappingInfoHandlerMapping
    implements EmbeddedValueResolverAware {
  // Expects a handler to have a type-level @{@link Controller} annotation.
  @Override
  protected boolean isHandler(Class<?> beanType) {
    return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
        AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
  }

  // Uses method and type-level @RequestMapping annotations to create the RequestMappingInfo.
  @Override
  protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    RequestMappingInfo info = createRequestMappingInfo(method);
    if (info != null) {
      RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
      if (typeInfo != null) {
        info = typeInfo.combine(info);
      }
      for (Map.Entry<String, Predicate<Class<?>>> entry : this.pathPrefixes.entrySet()) {
        if (entry.getValue().test(handlerType)) {
          String prefix = entry.getKey();
          if (this.embeddedValueResolver != null) {
            prefix = this.embeddedValueResolver.resolveStringValue(prefix);
          }
          info = RequestMappingInfo.paths(prefix).build().combine(info);
          break;
        }
      }
    }
    return info;
  }

  private RequestMappingInfo createRequestMappingInfo(AnnotatedElement element) {
    RequestMapping requestMapping = AnnotatedElementUtils.findMergedAnnotation(element, RequestMapping.class);
    RequestCondition<?> condition = (element instanceof Class ?
        getCustomTypeCondition((Class<?>) element) : getCustomMethodCondition((Method) element));
    return (requestMapping != null ? createRequestMappingInfo(requestMapping, condition) : null);
  }
}

public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping<RequestMappingInfo> {
}

public abstract class AbstractUrlHandlerMapping extends AbstractHandlerMapping {
  private final Map<PathPattern, Object> handlerMap = new LinkedHashMap<>();

  public Mono<Object> getHandlerInternal(ServerWebExchange exchange) {
    PathContainer lookupPath = exchange.getRequest().getPath().pathWithinApplication();
    Object handler;
    try {
      handler = lookupHandler(lookupPath, exchange);
    }
    catch (Exception ex) {
      return Mono.error(ex);
    }
    return Mono.justOrEmpty(handler);
  }

  protected Object lookupHandler(PathContainer lookupPath, ServerWebExchange exchange) throws Exception {

    List<PathPattern> matches = this.handlerMap.keySet().stream()
        .filter(key -> key.matches(lookupPath))
        .collect(Collectors.toList());

    if (matches.isEmpty()) {
      return null;
    }

    if (matches.size() > 1) {
      matches.sort(PathPattern.SPECIFICITYCOMPARATOR);
      if (logger.isTraceEnabled()) {
        logger.debug(exchange.getLogPrefix() + "Matching patterns " + matches);
      }
    }

    PathPattern pattern = matches.get(0);
    PathContainer pathWithinMapping = pattern.extractPathWithinPattern(lookupPath);
    return handleMatch(this.handlerMap.get(pattern), pattern, pathWithinMapping, exchange);
  }
}

public abstract class AbstractHandlerMapping extends ApplicationObjectSupport
    implements HandlerMapping, Ordered, BeanNameAware {
  public Mono<Object> getHandler(ServerWebExchange exchange) {
    return getHandlerInternal(exchange).map(handler -> {
      if (logger.isDebugEnabled()) {
        logger.debug(exchange.getLogPrefix() + "Mapped to " + handler);
      }
      if (hasCorsConfigurationSource(handler)) {
        ServerHttpRequest request = exchange.getRequest();
        CorsConfiguration config = (this.corsConfigurationSource != null ? this.corsConfigurationSource.getCorsConfiguration(exchange) : null);
        CorsConfiguration handlerConfig = getCorsConfiguration(handler, exchange);
        config = (config != null ? config.combine(handlerConfig) : handlerConfig);
        if (!this.corsProcessor.process(config, exchange) || CorsUtils.isPreFlightRequest(request)) {
          return REQUESTHANDLED_HANDLER;
        }
      }
      return handler;
    });
  }
}

Spring MVC在启动后AbstractUrlHandlerMapping中的handlerMap hashmap变量已设置完,key是URL Pattern,value是Controller bean

HandlerAdapter

上一步根据URL Pattern找到对应的Handler,现在根据Handler找HandlerAdapter, 并调用handler的handle方法处理请求。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class DispatcherServlet {
  protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
    //...
    ModelAndView mv = null;
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
}

  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");
  }
}

看org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter

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
  @Override
  public void afterPropertiesSet() throws Exception {
    // ...
    this.methodResolver = new ControllerMethodResolver(this.argumentResolverConfigurer,
        this.reactiveAdapterRegistry, this.applicationContext, this.messageReaders);

    this.modelInitializer = new ModelInitializer(this.methodResolver, this.reactiveAdapterRegistry);
  }

  @Override
  public boolean supports(Object handler) {
    return handler instanceof HandlerMethod;
  }

  @Override
  public Mono<HandlerResult> handle(ServerWebExchange exchange, Object handler) {
    HandlerMethod handlerMethod = (HandlerMethod) handler;
    Assert.state(this.methodResolver != null && this.modelInitializer != null, "Not initialized");

    InitBinderBindingContext bindingContext = new InitBinderBindingContext(
        getWebBindingInitializer(), this.methodResolver.getInitBinderMethods(handlerMethod));

    InvocableHandlerMethod invocableMethod = this.methodResolver.getRequestMappingMethod(handlerMethod);

    Function<Throwable, Mono<HandlerResult>> exceptionHandler =
        ex -> handleException(ex, handlerMethod, bindingContext, exchange);

    return this.modelInitializer
        .initModel(handlerMethod, bindingContext, exchange)
        .then(Mono.defer(() -> invocableMethod.invoke(exchange, bindingContext)))
        .doOnNext(result -> result.setExceptionHandler(exceptionHandler))
        .doOnNext(result -> bindingContext.saveModel())
        .onErrorResume(exceptionHandler);
  }

/
 * Package-private class to assist {@link RequestMappingHandlerAdapter} with
 * resolving, initializing, and caching annotated methods declared in
 * {@code @Controller} and {@code @ControllerAdvice} components. Assists with
 * the following annotations:
 * <ul>
 * <li>{@code @InitBinder}
 * <li>{@code @ModelAttribute}
 * <li>{@code @RequestMapping}
 * <li>{@code @ExceptionHandler}
 * </ul>
 *
 * @author Rossen Stoyanchev
 * @since 5.0
 */
class ControllerMethodResolver {
  /
   * Return an {@link InvocableHandlerMethod} for the given
   * {@code @RequestMapping} method initialized with argument resolvers.
   */
  public InvocableHandlerMethod getRequestMappingMethod(HandlerMethod handlerMethod) {
    InvocableHandlerMethod invocable = new InvocableHandlerMethod(handlerMethod);
    invocable.setArgumentResolvers(this.requestMappingResolvers);
    invocable.setReactiveAdapterRegistry(this.reactiveAdapterRegistry);
    return invocable;
  }
}

调用ControllerMethodResolver,解析@RequestMapping; 调用ModelInitializer,初始化

ModelAndView

onDispatch最后调用processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException)

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
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
  /**
   * 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,
      @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
      @Nullable 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.isTraceEnabled()) {
        logger.trace("No view rendering, null ModelAndView returned.");
      }
    }

    if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
      // Concurrent handling started during a forward
      return;
    }

    if (mappedHandler != null) {
      mappedHandler.triggerAfterCompletion(request, response, null);
    }
  }

  /**
   * Render the given ModelAndView.
   * <p>This is the last stage in handling a request. It may involve resolving the view by name.
   */
  protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
    // Determine locale for request and apply it to the response.
    Locale locale =
        (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
    response.setLocale(locale);

    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() + "'");
      }
    }
    else {
      // No need to lookup: the ModelAndView object contains the actual View object.
      view = mv.getView();
      if (view == null) {
        throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
            "View object in servlet with name '" + getServletName() + "'");
      }
    }

    // Delegate to the View object for rendering.
    if (logger.isTraceEnabled()) {
      logger.trace("Rendering view [" + view + "] ");
    }
    try {
      if (mv.getStatus() != null) {
        response.setStatus(mv.getStatus().value());
      }
      view.render(mv.getModelInternal(), request, response);
    }
    catch (Exception ex) {
      if (logger.isDebugEnabled()) {
        logger.debug("Error rendering view [" + view + "]", ex);
      }
      throw ex;
    }
  }

如果没异常的话调用render方法, 最后调用view的render方法

参考:https://hanxlinsist.github.io/Spring-MVC%E6%BA%90%E7%A0%81%E5%89%96%E6%9E%90/