第九章 DispatcherServlet源码分析笔记

本文详细分析了Spring MVC中DispatcherServlet的核心方法,包括HandlerMapping如何根据请求URL获取HandlerExecutionChain对象,如何封装HandlerMethod,以及前置、中置、后置过滤器的调用流程。此外,还讲解了Controller方法调用、返回值处理和视图渲染的步骤,揭示了Spring MVC处理HTTP请求的完整过程。
摘要由CSDN通过智能技术生成

一、dispatcherServlet的核心方法分析

当请求过来时,首先会调用到dispatcherServlet的doService方法,最终会调用到dispatcherServlet中的doDispatch方法。

该方法核心功能包含以下几点:

  • WebAsyncManager异步管理
  • processedRequest文件上传
  • HandlerMapping根据request对象获取获取HandlerMethod和过滤器链的包装类HandlerExecutionChain
  • HandlerAdapter映射关系处理,获取跟HandlerMethod匹配的HandlerAdapter对象
  • applyPreHandle前置过滤器,如果为false则直接返回
  • ha.handle调用到Controller具体方法,处理返回结果对象ModelAndView,核心方法调用
  • applyPostHandle中置过滤器,可以对ModelAndView对象进行修改
  • Render视图渲染
  • afterCompletion后置过滤器,资源释放
  • ExceptionHandler异常处理

1、HandlerMapping处理分析

1.1、根据请求url获取HandlerExecutionChain对象

org.springframework.web.servlet.DispatcherServlet#doDispatch

//这个方法很重要,重点看
// Determine handler for the current request.
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
   noHandlerFound(processedRequest, response);
   return;
}

寻找HandlerMethod的过程,感觉没什么好说的,前面映射关系已经建立好了,现在就是只需要从request对象中获取请求url,然后从映射关系中获取HandlerMethod对象就可以了,代码如下:

@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
   //从request对象中获取uri,/common/query2
   String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
   this.mappingRegistry.acquireReadLock();
   try {
      //根据uri从映射关系中找到对应的HandlerMethod对象
      HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
      //把Controller类实例化
      return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
   }finally {
      this.mappingRegistry.releaseReadLock();
   }
}

获取过程是,先从urlLookup中

List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
   //建立url和RequestMappingInfo映射关系
   this.urlLookup.add(url, mapping);
}

获取RequestMappingInfo对象,然后再跟进RequestMappingInfo对象从mappingLookup中

//建立uri对象和handlerMethod的映射关系
this.mappingLookup.put(mapping, handlerMethod);

获取HandlerMethod对象。

1.2、把HandlerMethod对象封装到HandlerExecutionChain对象

获取到HandlerMethod对象后,把HandlerMethod对象封装到HandlerExecutionChain对象中了。

org.springframework.web.servlet.DispatcherServlet#getHandler

@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   //handlerMappering实例
   if (this.handlerMappings != null) {
      for (HandlerMapping mapping : this.handlerMappings) {
         //获取HandlerMethod和过滤器链的包装类
         HandlerExecutionChain handler = mapping.getHandler(request);
         if (handler != null) {
            return handler;
         }
      }
   }
   return null;
}

1.3、获取HandlerMethod和过滤器链的包装类HandlerExecutionChain

org.springframework.web.servlet.handler.AbstractHandlerMapping#getHandler

@Override
@Nullable
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
   //根据请求的uri拿到对应的HandlerMethod对象
   Object handler = getHandlerInternal(request);
   if (handler == null) {
      handler = getDefaultHandler();
   }
   if (handler == null) {
      return null;
   }
   // Bean name or resolved handler?
   if (handler instanceof String) {
      String handlerName = (String) handler;
      handler = obtainApplicationContext().getBean(handlerName);
   }
   //获取HandlerMethod和过滤器链的包装类
   HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
   if (logger.isTraceEnabled()) {
      logger.trace("Mapped to " + handler);
   }
   else if (logger.isDebugEnabled() && !request.getDispatcherType().equals(DispatcherType.ASYNC)) {
      logger.debug("Mapped to " + executionChain.getHandler());
   }
   //是否是跨域请求,就是查看request请求头中是否有Origin属性
   if (CorsUtils.isCorsRequest(request)) {
      CorsConfiguration globalConfig = this.corsConfigurationSource.getCorsConfiguration(request);
      CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
      CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
      executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
   }
   return executionChain;
}

这个对象,启动就是封装了HandlerMethod和一个拦截器数组而已。

2、前置过滤器applyPreHandle

2.1、前置过滤器入口,如果为false则直接返回

org.springframework.web.servlet.DispatcherServlet#doDispatch

//前置过滤器,如果为false则直接返回
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
   return;
}

拿到HandlerExecutionChain对象进行过滤器的调用,调用了preHandle方法,只要这个方法返回为false,则后续请求就不会继续。

org.springframework.web.servlet.HandlerExecutionChain#applyPreHandle

boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
   HandlerInterceptor[] interceptors = getInterceptors();
   if (!ObjectUtils.isEmpty(interceptors)) {
      for (int i = 0; i < interceptors.length; i++) {
         HandlerInterceptor interceptor = interceptors[i];
         if (!interceptor.preHandle(request, response, this.handler)) {
            triggerAfterCompletion(request, response, null);
            return false;
         }
         this.interceptorIndex = i;
      }
   }
   return true;
}

2.2、interceptor.preHandle前置方法分析

 

com.chj.interceptor.UserInterceptor#preHandle

@Component
public class UserInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("======UserInterceptor用户权限校验=========");
        return true;
    }

2.3、如果前置返回false调用后置处理

org.springframework.web.servlet.HandlerExecutionChain#triggerAfterCompletion

 

/**
 * Trigger afterCompletion callbacks on the mapped HandlerInterceptors.
 * Will just invoke afterCompletion for all interceptors whose preHandle invocation
 * has successfully completed and returned true.
 */
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
      throws Exception {
   HandlerInterceptor[] interceptors = getInterceptors();
   if (!ObjectUtils.isEmpty(interceptors)) {
      for (int i = this.interceptorIndex; i >= 0; i--) {
         HandlerInterceptor interceptor = interceptors[i];
         try {
            interceptor.afterCompletion(request, response, this.handler, ex);
         }catch (Throwable ex2) {
            logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
         }
      }
   }
}

3、核心方法ha.handle调用

3.1、HandlerAdapter调用ha.handle核心方法

进行具体Controller中方法的调用这个调用过程,返回ModelAndView对象,关键点就在于参数的解析。

org.springframework.web.servlet.DispatcherServlet#doDispatch

//调用到Controller具体方法,核心方法调用,重点看看 Actually invoke the handler.
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

 

org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter#handle

@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
      throws Exception {
   return handleInternal(request, response, (HandlerMethod) handler);
}

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#handleInternal

@Override
protected ModelAndView handleInternal(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
   ModelAndView mav;
   checkRequest(request);
   // Execute invokeHandlerMethod in synchronized block if required.
   if (this.synchronizeOnSession) {
      HttpSession session = request.getSession(false);
      if (session != null) {
         Object mutex = WebUtils.getSessionMutex(session);
         synchronized (mutex) {
            mav = invokeHandlerMethod(request, response, handlerMethod);
         }
      } else { // No HttpSession available -> no mutex necessary
         mav = invokeHandlerMethod(request, response, handlerMethod);
      }
   } else {
      //Controller里面具体方法调用,重点看
      // No synchronization on session demanded at all...
      mav = invokeHandlerMethod(request, response, handlerMethod);
   }
   if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
      if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
         applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
      } else {
         prepareResponse(response);
      }
   }
   return mav;
}

3.2、Controller里面具体方法调用

该方法里面包括参数处理,返回对象分装处理等等。

org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter#invokeHandlerMethod

protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
      HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
   ServletWebRequest webRequest = new ServletWebRequest(request, response);
   try {
      //获取数据绑定工厂
      WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
      //Model工厂
      ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
      //可调用的方法对象
      ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
      if (this.argumentResolvers != null) {
         //设置参数解析器
         invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
      }
      if (this.returnValueHandlers != null) {
         //设置返回值解析器
         in

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值