spring boot webmvc mvc 核心类时序图

9 篇文章 0 订阅

使用spring  web mvc 时[spring boot 包含了 webmvc] 基本上会使用到

1. servlet 本身的 filter [不属于 mvc 层]

2. mvc 的 intercepter pre 和 post ,complete 调用, 含url路径筛选匹配

3. controller 执行,含 url 路径筛选匹配

4. 将返回的model的数据组装到对应的 View 中

3. mvc 的异常处理. @ExceptionHandler 或者全局的 @ControllerAdvice

要把这些逻辑组装在一起,还有概念

1. 核心流程类DispatcherServlet[是否是静态文件,负责为 url 找到对应的 controller,负责寻找和执行 intercepter,异常判断和处理]

2. ExceptionHandlerExceptionResolver exeptionHandler 的容器, 负责寻找匹配和执行异常处理逻辑.
     见附录的doResolveHandlerMethodException. 默认的处理类?

3.


附录:

  • error():37, CheckCommandController {com..platform.consistent.checker.controller}  Controller的@ExceptionHandler方法
  • invoke0():-1, NativeMethodAccessorImpl {sun.reflect}
  • invoke():62, NativeMethodAccessorImpl {sun.reflect}
  • invoke():43, DelegatingMethodAccessorImpl {sun.reflect}
  • invoke():498, Method {java.lang.reflect}
  • doInvoke():220, InvocableHandlerMethod {org.springframework.web.method.support}
  • invokeForRequest():134, InvocableHandlerMethod {org.springframework.web.method.support}
  • invokeAndHandle():116, ServletInvocableHandlerMethod {org.springframework.web.servlet.mvc.method.annotation}
  • doResolveHandlerMethodException():381, ExceptionHandlerExceptionResolver         {org.springframework.web.servlet.mvc.method.annotation} 
            Resolver容器找到对应的 handler 和 exception 的 ServletInvocableHandlerMethod,先exceptionHandlerCache,再从exceptionHandlerAdviceCache中获取. 代码如下
    ServletInvocableHandlerMethod exceptionHandlerMethod = getExceptionHandlerMethod(handlerMethod, exception);
    /**
     * Find an {@code @ExceptionHandler} method for the given exception. The default
     * implementation searches methods in the class hierarchy of the controller first
     * and if not found, it continues searching for additional {@code @ExceptionHandler}
     * methods assuming some {@linkplain ControllerAdvice @ControllerAdvice}
     * Spring-managed beans were detected.
     * @param handlerMethod the method where the exception was raised (may be {@code null})
     * @param exception the raised exception
     * @return a method to handle the exception, or {@code null}
     */
    protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) {
       Class<?> handlerType = (handlerMethod != null ? handlerMethod.getBeanType() : null);
    
       if (handlerMethod != null) {
          ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(handlerType);
          if (resolver == null) {
             resolver = new ExceptionHandlerMethodResolver(handlerType);
             this.exceptionHandlerCache.put(handlerType, resolver);
          }
          Method method = resolver.resolveMethod(exception);
          if (method != null) {
             return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method);
          }
       }
    
       for (Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry : this.exceptionHandlerAdviceCache.entrySet()) {
          if (entry.getKey().isApplicableToBeanType(handlerType)) {
             ExceptionHandlerMethodResolver resolver = entry.getValue();
             Method method = resolver.resolveMethod(exception);
             if (method != null) {
                return new ServletInvocableHandlerMethod(entry.getKey().resolveBean(), method);
             }
          }
       }
    
       return null;
    }
  • doResolveException():59, AbstractHandlerMethodExceptionResolver {org.springframework.web.servlet.handler}
  • resolveException():136, AbstractHandlerExceptionResolver {org.springframework.web.servlet.handler}
  • resolveException():74, HandlerExceptionResolverComposite {org.springframework.web.servlet.handler}
  • processHandlerException():1193, DispatcherServlet {org.springframework.web.servlet}
  • processDispatchResult():1030, DispatcherServlet {org.springframework.web.servlet}
  • doDispatch():980, DispatcherServlet {org.springframework.web.servlet}
      流程组装处,时序图最核心代码.
    /**
     * Process the actual dispatching to the handler.
     * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
     * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
     * to find the first that supports the handler class.
     * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
     * themselves to decide which methods are acceptable.
     * @param request current HTTP request
     * @param response current HTTP response
     * @throws Exception in case of any kind of processing failure
     */
    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 {
             processedRequest = checkMultipart(request);
             multipartRequestParsed = (processedRequest != request);
    
             // Determine handler for the current request.
             mappedHandler = getHandler(processedRequest);
             if (mappedHandler == null || mappedHandler.getHandler() == null) {
                noHandlerFound(processedRequest, response);
                return;
             }
    
             // Determine handler adapter for the current request.
             HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
    
             // Process last-modified header, if supported by the handler.
             String method = request.getMethod();
             boolean isGet = "GET".equals(method);
             if (isGet || "HEAD".equals(method)) {
                long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                if (logger.isDebugEnabled()) {
                   logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                }
                if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                   return;
                }
             }
    
             if (!mappedHandler.applyPreHandle(processedRequest, response)) { // phil 注: 先调用拦截器的 pre
                return;
             }
    
             // Actually invoke the handler.
             mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
             if (asyncManager.isConcurrentHandlingStarted()) {
                return;
             }
    
             applyDefaultViewName(processedRequest, mv);
             mappedHandler.applyPostHandle(processedRequest, response, mv); // phil 注: 后调用拦截器的 post
          }
          catch (Exception ex) {
             dispatchException = ex;
          }
          catch (Throwable err) {
             // As of 4.3, we're processing Errors thrown from handler methods as well,
             // making them available for @ExceptionHandler methods and other scenarios.
             dispatchException = new NestedServletException("Handler dispatch failed", err);
          }
          processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); // phil 注:1. exception 逻辑. exception 逻辑见上面堆栈注释.2.处理 view 的处理 3. mappedHandler.triggerAfterCompletion(request, response, null);
    
       }
       catch (Exception ex) {
          triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
       }
       catch (Throwable err) {
          triggerAfterCompletion(processedRequest, response, mappedHandler,
                new NestedServletException("Handler processing failed", err));
       }
       finally {
          if (asyncManager.isConcurrentHandlingStarted()) {
             // Instead of postHandle and afterCompletion
             if (mappedHandler != null) {
                mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
             }
          }
          else {
             // Clean up any resources used by a multipart request.
             if (multipartRequestParsed) {
                cleanupMultipart(processedRequest);
             }
          }
       }
    }
    /**
     * 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,
          HandlerExecutionChain mappedHandler, ModelAndView mv, 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.isDebugEnabled()) {
             logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
                   "': assuming HandlerAdapter completed request handling");
          }
       }
    
       if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
          // Concurrent handling started during a forward
          return;
       }
    
       if (mappedHandler != null) {
          mappedHandler.triggerAfterCompletion(request, response, null); // phil注: intercepter 的 complete
       }
    }

     
  • doService():897, DispatcherServlet {org.springframework.web.servlet}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值