SpringMVC源码分析 (2022.08.23)

SpringBoot-SpringMVC源码分析 (2022.08.23)

补充一波SpringMVC源码分析, 请求至响应分析 (版本: v5.3.6)

核心组件:

  • 核心前端控制器: (用于拦截请求,获取url),
  • 处理器映射器:(用于找到需要处理的执行链或者方法参数),
  • 处理器适配器: (根据执行链用于找到合适的处理程序进行处理)
  • 处理器 与 拦截器: 用于执行执行链!
  • 请求参数解析器与类型转换器: 用于解析与转换请求参数绑定到处理器方法
  • 响应参数解析器与消息转换器: 用于解析与转换响应参数;
  • 视图: 一个接口可以支持返回不同页面,(html,jsp)
  • 视图解析器与渲染器: (用于解析与渲染返回的视图)
  • 异常解析器: 用于解决执行处理器出现的异常

容器启动之初会初始化的组件

处理器映射器

会扫描创建好URL : 处理器, 封装进一个Map;

入口类: RequestMappingHandlerMapping

注册映射:

当应用上下文创建该RequestMappingHandlerMapping 时候, 创建完Bean后会触发后续一些操作, 进行注册URL : 处理器 封装进一个Map中;

// RequestMappingHandlerMapping.java
public void afterPropertiesSet() {
	// 映射一些配置
   this.config = new RequestMappingInfo.BuilderConfiguration();
   this.config.setTrailingSlashMatch(useTrailingSlashMatch());
   this.config.setContentNegotiationManager(getContentNegotiationManager());

   if (getPatternParser() != null) {
      this.config.setPatternParser(getPatternParser());
      Assert.isTrue(!this.useSuffixPatternMatch && !this.useRegisteredSuffixPatternMatch,
            "Suffix pattern matching not supported with PathPatternParser.");
   }
   else {
      this.config.setSuffixPatternMatch(useSuffixPatternMatch());
      this.config.setRegisteredSuffixPatternMatch(useRegisteredSuffixPatternMatch());
      this.config.setPathMatcher(getPathMatcher());
   }
	// 调用父类AbstractHandlerMethodMapping 的afterPropertiesSet方法
   super.afterPropertiesSet();
}
// AbstractHandlerMethodMapping
@Override
public void afterPropertiesSet() {
   initHandlerMethods();
}

protected void initHandlerMethods() {
    // obtainApplicationContext().getBeanNamesForType(Object.class) 获取应用上下文所有注册的bean名称
		for (String beanName : getCandidateBeanNames()) {
			if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
				processCandidateBean(beanName);
			}
		}
    // 所有URL => 处理器 映射完毕后调用, 获取到对应Map, 然后handlerMethodsInitialized 输出日志
		handlerMethodsInitialized(getHandlerMethods());
	}

protected void processCandidateBean(String beanName) {
		Class<?> beanType = null;
		try {
            // 获取对应Bean类型
			beanType = obtainApplicationContext().getType(beanName);
		}
		catch (Throwable ex) {
			// An unresolvable bean type, probably from a lazy bean - let's ignore it.
			if (logger.isTraceEnabled()) {
				logger.trace("Could not resolve type for bean '" + beanName + "'", ex);
			}
		}
    	// 判断是否是处理器
		if (beanType != null && isHandler(beanType)) {
			detectHandlerMethods(beanName);
		}
	}
// RequestMappingHandlerMapping.java
protected boolean isHandler(Class<?> beanType) {
   return (AnnotatedElementUtils.hasAnnotation(beanType, Controller.class) ||
         AnnotatedElementUtils.hasAnnotation(beanType, RequestMapping.class));
}
// AbstractHandlerMethodMapping
protected void detectHandlerMethods(Object handler) {
    // 获取处理器类型
   Class<?> handlerType = (handler instanceof String ?
         obtainApplicationContext().getType((String) handler) : handler.getClass());

   if (handlerType != null) {
       // 获取定义类型, 防止获取到生成的子类
      Class<?> userType = ClassUtils.getUserClass(handlerType);
       // 
      Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
            (MethodIntrospector.MetadataLookup<T>) method -> {
               try {
                   // 获取方法映射
                  return getMappingForMethod(method, userType);
               }
               catch (Throwable ex) {
                  throw new IllegalStateException("Invalid mapping on handler class [" +
                        userType.getName() + "]: " + method, ex);
               }
            });
      if (logger.isTraceEnabled()) {
         logger.trace(formatMappings(userType, methods));
      }
      else if (mappingsLogger.isDebugEnabled()) {
         mappingsLogger.debug(formatMappings(userType, methods));
      }
      methods.forEach((method, mapping) -> {
         Method invocableMethod = AopUtils.selectInvocableMethod(method, userType);
         registerHandlerMethod(handler, invocableMethod, mapping);
      });
   }
}

v618KJ.png

处理器适配器

入口 WebMvcConfigurationSupport # requestMappingHandlerAdapter()

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(
      @Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
      @Qualifier("mvcConversionService") FormattingConversionService conversionService,
      @Qualifier("mvcValidator") Validator validator) {
	
   // 创建请求映射处理器适配器
   RequestMappingHandlerAdapter adapter = createRequestMappingHandlerAdapter();
   adapter.setContentNegotiationManager(contentNegotiationManager);
    // 设置消息转换器集合
   adapter.setMessageConverters(getMessageConverters());
    // 设置数据绑定
   adapter.setWebBindingInitializer(getConfigurableWebBindingInitializer(conversionService, validator));
    // 设置自定义参数转换解析器
   adapter.setCustomArgumentResolvers(getArgumentResolvers());
    // 设置自定义返回值转换处理程序
   adapter.setCustomReturnValueHandlers(getReturnValueHandlers());

   if (jackson2Present) {
      adapter.setRequestBodyAdvice(Collections.singletonList(new JsonViewRequestBodyAdvice()));
      adapter.setResponseBodyAdvice(Collections.singletonList(new JsonViewResponseBodyAdvice()));
   }

   AsyncSupportConfigurer configurer = getAsyncSupportConfigurer();
   if (configurer.getTaskExecutor() != null) {
      adapter.setTaskExecutor(configurer.getTaskExecutor());
   }
   if (configurer.getTimeout() != null) {
      adapter.setAsyncRequestTimeout(configurer.getTimeout());
   }
   adapter.setCallableInterceptors(configurer.getCallableInterceptors());
   adapter.setDeferredResultInterceptors(configurer.getDeferredResultInterceptors());

   return adapter;
}
设置Http消息转换器

v6amVg.md.png

设置参数转换和绑定器 (其他博客说明)

v6IQ74.png

设置参数解析器/返回参数处理器

RequestBodyAdvice和ResponseBodyAdvice接口 (针对于@RequestBody@ResponseBody, 参数处理增强)

非使用@RequestBody@ResponseBody, 参考 框架提供的 自定义实现一个参数解析器、响应参数处理 (扩展1.0有个简单例子)

vc9bFI.png

1

适配器完结:

v6au5j.png

请求开始至响应流程

请求是如何找到对应控制器类中对应方法, 转换参数进行执行的呢?

入口类: org.springframework.web.servlet.DispatcherServlet # doService()

doService() 方法只是设置了请求域中的一些属性, 然后会接着调用doDispatch(request, response) 这个方法才是真正的请求后续大量处理入口

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
   HttpServletRequest processedRequest = request;
   HandlerExecutionChain mappedHandler = null;
   boolean multipartRequestParsed = false;
	// 获取异步请求管理器 (https://www.cnblogs.com/deityjian/p/11503218.html)
   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) {
            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;
            }
         }

         if (!mappedHandler.applyPreHandle(processedRequest, response)) {
            return;
         }

         // Actually invoke the handler.
         mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

         if (asyncManager.isConcurrentHandlingStarted()) {
            return;
         }

         applyDefaultViewName(processedRequest, mv);
         mappedHandler.applyPostHandle(processedRequest, response, mv);
      }
      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);
         }
      }
   }
}

检测是否是文件上传

v6GqII.png

通过请求找处理器映射器

mappedHandler = getHandler(processedRequest)

vclYGT.png

同时找到了处理器和执行链HandlerExecutionChain handler = mapping.getHandler(request)

通过处理器找适配器并执行任务链

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

vc3Ub9.png

通过适配器执行处理器获取视图

vcNPEQ.png

获取到视图的后续处理

vcNs2t.png

到此整个请求处理过程的关键步骤都分析完了。理解了SpringMVC V5.x版本上中的请求处理流程;

核心前端控制器执行异常情况

vcUJij.png

扩展

1.0 自定义参数解析器( 到达controller前处理请求参数)

甚至可以定义添加Converters参数转换器来实现

@Configuration
public class MyMVCConfig implements WebMvcConfigurer {
@Override
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
    resolvers.add(new HandlerMethodArgumentResolver() {
        // post请求 json交互可以使用实现Advice接口增加请求前参数处理
        // 非json交互 post, get请求, 方法参数实体,  参考 ServletModelAttributeMethodProcessor实现 
        // 非json交互 get 请求, 方法参数非实体  参考 RequestParamMethodArgumentResolver实现
        @Override
        public boolean supportsParameter(MethodParameter parameter) {
            return parameter.getParameter().getParameterizedType() == UserOne.class;
        }

        @Override
        public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
            Class parameterizedType = (Class) parameter.getParameter().getParameterizedType();
            Object target = parameterizedType.newInstance();
            WebDataBinder binder = binderFactory.createBinder(webRequest, target, parameter.getParameter().getName());
            ServletRequest servletRequest = webRequest.getNativeRequest(ServletRequest.class);
            ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
            servletBinder.bind(servletRequest);
            return binder.getBindingResult().getTarget();
        }
    });
    WebMvcConfigurer.super.addArgumentResolvers(resolvers);
}

2.0 自定义响应参数处理程序

一般使用@ResponseBody 返回的使用Advice接口

返回视图的参考: ViewNameMethodReturnValueHandler , 或者在源码HandlerMethodReturnValueHandlerComposite#handleReturnValue() 参考返回值使用的是那个, 参考着写

1

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

懵懵懂懂程序员

如果节省了你的时间, 请鼓励

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值