SpringMVC源码解析DispatcherServlet#doDispatch方法流程(下)

简介: SpringMVC源码解析DispatcherServlet#doDispatch方法流程(下)

getHandler(processedRequest);

  • 为此请求返回HandlerExecutionChain。按顺序尝试所有的handler mapping
  • image.png
  • 获取当前请求对应的处理类,在这个处理链中会包含对应的拦截器的信息。HandlerExecutionChain这个类中包含变和不变量的两部分内容
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  for (HandlerMapping hm : this.handlerMappings) {
    HandlerExecutionChain handler = hm.getHandler(request);
    if (handler != null) {
      return handler;
    }
  }
  return null;
}

循环handlerMappings,然后获取对应的执行链,只要找到一个对应的执行链就返回


SpringMVC默认加载三个请求处理映射类:


RequestMappingHandlerMapping

SimpleUrlHandlerMapping

BeanNameUrlHandlerMapping

这三个类有一个共同的父类:AbstractHandlerMapping。


hm.getHandler(request)这个getHandler方法在AbstractHandlerMapping中,它的子类都没有重写这个方法。

AbstractHandlerMethodMapping#getHandler

@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  // 两个子类重写该方法:AbstractHandlerMethodMapping和AbstractUrlHandlerMapping
  Object handler = getHandlerInternal(request);
  // 如果没有找到的话,默认处理类
  if (handler == null) {
    handler = getDefaultHandler();
  }
  // 如果没有默认的处理类,返回null
  if (handler == null) {
    return null;
  }
  // Bean name or resolved handler?
  if (handler instanceof String) {
    String handlerName = (String) handler;
    handler = getApplicationContext().getBean(handlerName);
  }
  // 包装为执行器链
  HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
  // 是不是跨域请求
  if (CorsUtils.isCorsRequest(request)) {
    CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
    CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
    CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
    executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
  }
  return executionChain;
}

AbstractHandlerMethodMapping#getHandlerInternal

  @Override
  protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
    // 得到请求 url 的查询路径
    String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
    }
    // 获取并发读锁
    this.mappingRegistry.acquireReadLock();
    try {
      // 得到查询路径对应的处理器方法
      HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
      return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
    }
    finally {
      this.mappingRegistry.releaseReadLock();
    }
  }

getHandlerExecutionChain

创建执行器链的内容:

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
  //判断handler是不是执行器链,如果不是创建一个执行器链
  HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
      (HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
  String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
  //包装拦截器
  for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
    if (interceptor instanceof MappedInterceptor) {
      MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
      if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
        chain.addInterceptor(mappedInterceptor.getInterceptor());
      }
    }
    else {
      chain.addInterceptor(interceptor);
    }
  }
  return chain;
}

这个方法主要是创建执行器链,添加拦截器.

判断

if (mappedHandler == null || mappedHandler.getHandler() == null) {
  noHandlerFound(processedRequest, response);
  return;
}

如果没有找到对应的处理类的话,这里通常会返回404,如果throwExceptionIfNoHandlerFound属性值为true的情况下会抛出异常。

我们继续往下分析:

HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

getHandlerAdapter

获取处理适配器

image.png

SimpleControllerHandlerAdapter

适配SimpleUrlHandlerMapping和BeanNameUrlHandlerMapping的映射的,也就是实现Controller接口的Handler

AbstractHandlerMethodAdapter

适配RequestMappingHandlerMapping,也就是我们常用的RequestMapping注解

HttpRequestHandlerAdapter

适配远程调用的

SimpleServletHandlerAdapter

适配Servlet实现类的

supports

image.png

supportsInternal

总是返回true ,因为任何方法参数和返回值类型会以某种方式加以处理。

不被任何HandlerMethodArgumentResolver识别的方法参数被解释为一个请求参数,如果它是一个简单的类型,或者作为模型属性否则。

没有任何HandlerMethodReturnValueHandler识别的返回值将被解释为一个模型属性

image.png

如果是GET请求,内容没有变化则直接返回

applyPreHandle

  • 应用已注册的preHandle拦截方法
  • image.png
  • image.png

handle()

mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

执行handle

applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);

如果返回的mv不为null,并且没有设置view,则设置默认的view

应用postHandle拦截器。

processDispatchResult

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) {
      mv = ((ModelAndViewDefiningException) exception).getModelAndView();
    }
    else {
      Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
      mv = processHandlerException(request, response, handler, exception);
      errorView = (mv != null);
    }
  }
  //返回的ModelAndView不为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 (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
    // Concurrent handling started during a forward
    return;
  }
  // 调用处理拦截器的afterCompletion
  if (mappedHandler != null) {
    mappedHandler.triggerAfterCompletion(request, response, null);
  }
}

如果


出现异常,返回异常页面

没有异常,ModelAndView不为null,则正常渲染页面,调用拦截器的afterCompletion方法


目录
相关文章
|
3天前
PandasTA 源码解析(二十三)
PandasTA 源码解析(二十三)
27 0
|
3天前
PandasTA 源码解析(二十二)(3)
PandasTA 源码解析(二十二)
22 0
|
3天前
PandasTA 源码解析(二十二)(2)
PandasTA 源码解析(二十二)
18 2
|
3天前
PandasTA 源码解析(二十二)(1)
PandasTA 源码解析(二十二)
18 0
|
3天前
PandasTA 源码解析(二十一)(4)
PandasTA 源码解析(二十一)
14 1
|
3天前
PandasTA 源码解析(二十一)(3)
PandasTA 源码解析(二十一)
14 0
|
3天前
PandasTA 源码解析(二十一)(2)
PandasTA 源码解析(二十一)
17 1
|
3天前
PandasTA 源码解析(二十一)(1)
PandasTA 源码解析(二十一)
13 2
|
3天前
PandasTA 源码解析(二十)(1)
PandasTA 源码解析(二十)
9 0
|
3天前
PandasTA 源码解析(十九)(3)
PandasTA 源码解析(十九)
11 2

推荐镜像

更多