美文网首页
SpringMVC请求处理

SpringMVC请求处理

作者: 林亚希 | 来源:发表于2022-11-16 09:27 被阅读0次

    SpringMVC 请求处理流程

    SpringMVC运行流程图.jpg

    1. DispatcherServlet 九大组件

    //DispatcherServlet中的九大组件、全是接口,我们完全可以自定义实现。Spring默认也都准备好了这些组件的实现
    /** MultipartResolver used by this servlet. */ //https://docs.spring.io/spring-framework/docs/current/reference/html/web.html#mvc-servlet-special-bean-types
    @Nullable  //文件上传解析器
    private MultipartResolver multipartResolver;
    
    /** LocaleResolver used by this servlet. */
    @Nullable  //国际化解析器 Locale(区域信息)
    private LocaleResolver localeResolver;
    
    /** ThemeResolver used by this servlet. */
    @Nullable //主题解析器
    private ThemeResolver themeResolver;
    
    /** List of HandlerMappings used by this servlet. */
    @Nullable //Handler(处理器、能处理请求的人(Controller))的映射:【保存的就是所有请求都由谁来处理的映射关系】
    private List<HandlerMapping> handlerMappings;
    
    /** List of HandlerAdapters used by this servlet. */
    @Nullable //Handler(处理器、能处理请求的人(Controller))的适配器;【超级反射工具】
    private List<HandlerAdapter> handlerAdapters;
    
    /** List of HandlerExceptionResolvers used by this servlet. */
    @Nullable //Handler的异常解析器,异常处理功能
    private List<HandlerExceptionResolver> handlerExceptionResolvers;
    
    /** RequestToViewNameTranslator used by this servlet. */
    @Nullable //把请求转成视图名(我们要跳转的页面地址)的翻译器【没啥用】
    private RequestToViewNameTranslator viewNameTranslator;
    
    /** FlashMapManager used by this servlet. */
    @Nullable //闪存管理器
    private FlashMapManager flashMapManager;
    
    /** List of ViewResolvers used by this servlet. */
    @Nullable //视图解析器(我们去哪些页面,怎么过去?)
    private List<ViewResolver> viewResolvers;
    

    2. DispatcherServlet 初始化

    /**
     * This implementation calls {@link #initStrategies}.
     */
    @Override //
    protected void onRefresh(ApplicationContext context) {
       initStrategies(context); //初始化九大组件
    }
    
    /**
     * Initialize the strategy objects that this servlet uses.
     * <p>May be overridden in subclasses in order to initialize further strategy objects.
     */
    protected void initStrategies(ApplicationContext context) { //初始化所有策略,九大组件在这里进行了初始化
       initMultipartResolver(context); //容器中有就用,没有就是null 解析请求
       initLocaleResolver(context); //从容器中获取,没有用默认 国际化
       initThemeResolver(context); //从容器中获取,没有用默认 主题
       initHandlerMappings(context); //从容器中获取,没有用默认 (处理器、能处理请求的人(Controller))的映射:【保存的就是所有请求都由谁来处理的映射关系】
       initHandlerAdapters(context); //从容器中获取,没有用默认 Handler(处理器、能处理请求的人(Controller))的适配器;【超级反射工具】
       initHandlerExceptionResolvers(context); //从容器中获取,没有用默认  Handler的异常解析器,异常处理功能
       initRequestToViewNameTranslator(context); //Spring没有浓重说他,//从容器中获取,没有用默认 初始化视图转发
       initViewResolvers(context); //从容器中获取,没有用默认 初始化视图解析器,将ModelAndView保存的视图信息,转换为一个视图,输出数据
       initFlashMapManager(context); //从容器中获取,没有用默认 闪存管理器
    }
    

    我们可以在这里打断点,发现进入这里的方法是FrameworkServlet->initWebApplicationContext->configureAndRefreshWebApplicationContext(cwac); //配置并且刷新容器 通过监听事件回调到onRefresh。

    2.1 加载默认策略

    private void initLocaleResolver(ApplicationContext context) {
       try { //容器中先来获取
          this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
          if (logger.isTraceEnabled()) {
             logger.trace("Detected " + this.localeResolver);
          }
          else if (logger.isDebugEnabled()) {
             logger.debug("Detected " + this.localeResolver.getClass().getSimpleName());
          }
       }
       catch (NoSuchBeanDefinitionException ex) {
          // We need to use the default. 容器中没有,读取默认配置文件进行加载
          this.localeResolver = getDefaultStrategy(context, LocaleResolver.class); //获取默认策略
          if (logger.isTraceEnabled()) {
             logger.trace("No LocaleResolver '" + LOCALE_RESOLVER_BEAN_NAME +
                   "': using default [" + this.localeResolver.getClass().getSimpleName() + "]");
          }
       }
    }
    

    这边获取默认配置文件策略可以看下

    3. DispatcherServlet doService

    @Override
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
       logRequest(request);
    
       // Keep a snapshot of the request attributes in case of an include,
       // to be able to restore the original attributes after the include.
       Map<String, Object> attributesSnapshot = null; //把request域的所有属性提前保存
       if (WebUtils.isIncludeRequest(request)) {
          attributesSnapshot = new HashMap<>();
          Enumeration<?> attrNames = request.getAttributeNames();
          while (attrNames.hasMoreElements()) {
             String attrName = (String) attrNames.nextElement();
             if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
                attributesSnapshot.put(attrName, request.getAttribute(attrName)); //快照所有属性
             }
          }
       }
    
       //基本的东西保存到request域中方便处理 Make framework objects available to handlers and view objects.
       request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
       request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver); //国际化解析器
       request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver); //主题解析器
       request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());
    
       if (this.flashMapManager != null) { //闪存管理器(重定向携带数据)
          FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
          if (inputFlashMap != null) {
             request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
          }
          request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
          request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
       }
    
       RequestPath previousRequestPath = null;
       if (this.parseRequestPath) {
          previousRequestPath = (RequestPath) request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
          ServletRequestPathUtils.parseAndCache(request);
       }
    
       try {
          doDispatch(request, response); //【核心】处理派发功能
       }
       finally {
          if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
             // Restore the original attribute snapshot, in case of an include.
             if (attributesSnapshot != null) {
                restoreAttributesAfterInclude(request, attributesSnapshot);
             }
          }
          ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
       }
    }
    

    3.1【核心】处理派发功能

    //SpringMVC处理请求的核心流程
    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
       HttpServletRequest processedRequest = request;
       HandlerExecutionChain mappedHandler = null; //handler(目标方法)的执行链
       boolean multipartRequestParsed = false; //文件上传标志
       //对异步请求的支持(Servlet3.0以后才有的,Webflux)
       WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
    
       try {
          ModelAndView mv = null;
          Exception dispatchException = null;
    
          try {
             processedRequest = checkMultipart(request); //检查当前是否文件上传请求
             multipartRequestParsed = (processedRequest != request);
    
             //构造出了【目标方法+拦截器整个链路】决定使用哪个Handler处理当前请求 Determine handler for the current request.
             mappedHandler = getHandler(processedRequest);
             if (mappedHandler == null) {  //如果找不到人处理,就send 404
                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 (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                   return;
                }
             }
             //所有拦截器的 preHandle 执行
             if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                return; //使用 mappedHandler整个链
             }
    
             //真正来执行目标方法 Actually invoke the handler.(反射执行目标方法、确定参数值,处理返回值【封装成ModelAndView】)
             mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
             if (asyncManager.isConcurrentHandlingStarted()) {
                return;
             }
    
             applyDefaultViewName(processedRequest, mv);
             mappedHandler.applyPostHandle(processedRequest, response, mv); //所有拦截器的postHandle
          }
          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);
       }
       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);
             }
          }
       }
    }
    
    3.1.1 mappedHandler = getHandler(processedRequest); 构造出了【目标方法+拦截器整个链路】决定使用哪个Handler处理当前请求
    @Nullable //所有 策略模式 ,尝试每一个策略。
    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;
    }
    

    HandlerMapping 在我们注册的九大组件的时候初始化进来的。

    进去看看这个方法 HandlerExecutionChain handler = mapping.getHandler(request);

    @Override
    @Nullable
    public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
       Object handler = getHandlerInternal(request); //HandlerMapping的registry中找映射,返回HandlerMethod,真正执行当前请求的方法
       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);
       }
    
       // Ensure presence of cached lookupPath for interceptors and others
       if (!ServletRequestPathUtils.hasCachedPath(request)) {
          initLookupPath(request);
       }
       //找到前面的目标方法以后,还要构造一个处理器链;
       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());
       }
    
       if (hasCorsConfigurationSource(handler) || CorsUtils.isPreFlightRequest(request)) {
          CorsConfiguration config = getCorsConfiguration(handler, request);
          if (getCorsConfigurationSource() != null) {
             CorsConfiguration globalConfig = getCorsConfigurationSource().getCorsConfiguration(request);
             config = (globalConfig != null ? globalConfig.combine(config) : config);
          }
          if (config != null) {
             config.validateAllowCredentials();
          }
          executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
       }
    
       return executionChain;
    }
    
    @Override
    protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
       String lookupPath = initLookupPath(request);
       this.mappingRegistry.acquireReadLock();
       try {
          HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); //寻找当前请求谁能处理
          return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
       }
       finally {
          this.mappingRegistry.releaseReadLock();
       }
    }
    

    就是在mappingRegistry 里面查找谁能够处理当前的请求。那么mappingRegistry什么时候注册进去的?

    注册mappingRegistry
    //分析所有的Controller;里面的每一个@RequestMapping 注解才能知道这个事情
    public void registerMapping(T mapping, Object handler, Method method) { //哪个请求由哪个方法处理会通过这个进行注册
       if (logger.isTraceEnabled()) {
          logger.trace("Register \"" + mapping + "\" to " + method.toGenericString());
       }
       this.mappingRegistry.register(mapping, handler, method);
    }
    

    AbstractHandlerMethodMapping

    public void register(T mapping, Object handler, Method method) {
       this.readWriteLock.writeLock().lock();
       try {
          HandlerMethod handlerMethod = createHandlerMethod(handler, method);
          validateMethodMapping(handlerMethod, mapping);
    
          Set<String> directPaths = AbstractHandlerMethodMapping.this.getDirectPaths(mapping);
          for (String path : directPaths) {
             this.pathLookup.add(path, mapping);
          }
    
          String name = null;
          if (getNamingStrategy() != null) {
             name = getNamingStrategy().getName(handlerMethod, mapping);
             addMappingName(name, handlerMethod);
          }
    
          CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
          if (corsConfig != null) {
             corsConfig.validateAllowCredentials();
             this.corsLookup.put(handlerMethod, corsConfig);
          }
    
          this.registry.put(mapping,
                new MappingRegistration<>(mapping, handlerMethod, directPaths, name, corsConfig != null));
       }
       finally {
          this.readWriteLock.writeLock().unlock();
       }
    }
    

    我们可以在这里打个断点看看

    我们发现AbstractHandlerMethodMapping 是继承InitializingBean。我们之前挖坑的。后置增强会调用afterPropertiesSet方法,这个可以自己去跟一下

    private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
          @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
          @Nullable Exception exception) throws Exception {
    
       boolean errorView = false;
       //如果有异常处理异常,以下if内全是异常处理环节
       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?   为啥?@ResponseBody(提前在解析返回值的时候,就已经把数据写出去了,所以这一步就没有了)
       if (mv != null && !mv.wasCleared()) {
          render(mv, request, response); //渲染ModeAndView,来解析模型和视图;最终决定响应效果
          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) {
          // Exception (if any) is already handled..
          mappedHandler.triggerAfterCompletion(request, response, null);
       }
    }
    
    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);
       //默认AcceptHeaderLocaleResolver会根据请求头中的Accept-Language字段决定浏览器能接受哪种中文/英文 页面
       View view; //视图
       String viewName = mv.getViewName(); //适配器执行完目标方法以后返回的ModelAndView对象里面有  index.jsp
       if (viewName != null) {
          //************ 把目标方法的返回值字符串index.jsp 真正转为能用的View对象; 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;
       }
    }
    

    相关文章

      网友评论

          本文标题:SpringMVC请求处理

          本文链接:https://www.haomeiwen.com/subject/msnjgrtx.html