1.SpringMVC核心流程图
#SpringMVC具体解析步骤:
第一步:发起请求到前端控制器(DispatcherServlet)
第二步:前端控制器请求HandlerMapping查找 Handler (可以根据xml配置、注解进行查找)
第三步:处理器映射器HandlerMapping向前端控制器返回Handler,
HandlerMapping会把请求映射为HandlerExecutionChain对象(包含一个Handler处理器(页面控制器)对象,
多个HandlerInterceptor拦截器对象), 通过这种策略模式,很容易添加新的映射策略
第四步:前端控制器调用处理器适配器去执行Handler
第五步:处理器适配器HandlerAdapter将会根据适配的结果去执行Handler
第六步:Handler执行完成给适配器返回ModelAndView
第七步:处理器适配器向前端控制器返回ModelAndView ModelAndView是springmvc框架的一个底层对象,包括 Model和view
第八步:前端控制器请求视图解析器去进行视图解析
根据逻辑视图名解析成真正的视图(jsp),通过这种策略很容易更换其他视图技术,只需要更改视图解析器即可
第九步:视图解析器向前端控制器返回View
第十步:前端控制器进行视图渲染
视图渲染将模型数据(在ModelAndView对象中)填充到request域
第十一步:前端控制器向用户响应结果
#总结 核心开发步骤(SpringMVC, 非 SpringBoot)
1.DispatcherServlet 在 web.xml 中的部署描述,从而拦截请求到 Spring Web MVC
2.HandlerMapping 的配置,从而将请求映射到处理器
3.HandlerAdapter 的配置,从而支持多种类型的处理器
注:处理器映射求和适配器使用注解(如@RequestMapping)的话包含在了注解驱动中,不需要再单独配置
4.ViewResolver 的配置,从而将逻辑视图名解析为具体视图技术
5.处理器(页面控制器)的配置,从而进行功能处理
6.View是一个接口,实现类支持不同的View类型(jsp, freemarker, pdf...)
2.源码分析
2.1 核心类DispatcherServlet 分析
#访问一个RequestMapping时main线程调用链--后半部分
--> DispatcherServlet#doDispatch
--> DispatcherServlet#checkMultipart
// StringUtils.startsWithIgnoreCase(request.getContentType(), "multipart/") ?
--> StandardServletMultipartResolver#isMultipart
--> StandardServletMultipartResolver#resolveMultipart
--> StandardMultipartHttpServletRequest#StandardMultipartHttpServletRequest(HttpServletRequest, boolean)
--> StandardMultipartHttpServletRequest#parseRequest
--> AbstractMultipartHttpServletRequest#setMultipartFiles
// WebEndpointServletHandlerMapping, ControllerEndpointHandlerMapping, BeanNameHandlerMapping
// RequestMappingHandlerMapping --> @RequestMapping 注解对应的 handlerMapping --> 这里运用到了 策略模式
// 这一步获取 handler 及 interceptorList (拦截器列表), 若为空, 则报 404 或其他错误
--> DispatcherServlet#getHandler
--> AbstractHandlerMapping#getHandler
--> AbstractHandlerMapping#getHandlerExecutionChain
// HttpRequestHandlerAdapter, SimpleControllerHandlerAdapter
// RequestMappingHandlerAdapter --> @RequestMapping 注解对应的 handlerAdapter
// 传入 handler, 获取 HandlerAdapter --> 这里运用到了 策略模式
--> DispatcherServlet#getHandlerAdapter
// 遍历上文获得的 interceptors 数组, 调用各个 HandlerInterceptor 的 preHandle 方法
--> HandlerExecutionChain#applyPreHandle
--> HandlerInterceptor#preHandle
// 真正开始 通过 HandlerAdapter 调用 handler, 如 RequestMappingHandlerAdapter, 返回 ModelAndView
--> AbstractHandlerMethodAdapter#handle
--> RequestMappingHandlerAdapter#handleInternal
--> RequestMappingHandlerAdapter#invokeHandlerMethod
// 通过反射使用 controller 调用 service 层方法
--> ServletInvocableHandlerMethod#invokeAndHandle
--> ServletInvocableHandlerMethod#invokeAndHandle
--> InvocableHandlerMethod#invokeForRequest
// 参数解析部分
--> InvocableHandlerMethod#getMethodArgumentValues
// this.resolvers.supportsParameter(parameter)
// this.resolvers.resolveArgument: 这一步中, 解析参数的过程中, 也可能会经过 HttpMessageConverter
--> HandlerMethodArgumentResolverComposite#resolveArgument
// 如果加了 @RequestBody 注解, 将会走进这个方法, 最终经过 HttpMessageConverter 转换
--> RequestResponseBodyMethodProcessor#resolveArgument
--> RequestResponseBodyMethodProcessor#readWithMessageConverters
--> AbstractMessageConverterMethodArgumentResolver#readWithMessageConverters(HttpInputMessage, MethodParameter, Type)
// 真正通过反射执行方法调用的部分
--> InvocableHandlerMethod#doInvoke
--> HandlerMethodReturnValueHandlerComposite#handleReturnValue
// 这里以 加了 @ResponseBody 注解 以及 org.springframework.http.MediaType 值的 controller 为例
--> RequestResponseBodyMethodProcessor#handleReturnValue
--> AbstractMessageConverterMethodProcessor#writeWithMessageConverters(T, MethodParameter, ServletServerHttpRequest, ServletServerHttpResponse)
// SpringBoot 中默认的 MessageConverter --> MappingJackson2HttpMessageConverter
// genericConverter.write(body, targetType, selectedMediaType, outputMessage);
// 序列化方式
MappingJackson2HttpMessageConverter.write
// this.returnValueHandlers.handleReturnValue
--> HandlerMethodReturnValueHandlerComposite#handleReturnValue
--> HandlerMethodReturnValueHandlerComposite#selectHandler
// handler.handleReturnValue, 如果加了 @ResponseBody 注解, 将会走进这个方法, 最终经过 HttpMessageConverter 转换
--> RequestResponseBodyMethodProcessor#handleReturnValue
--> AbstractMessageConverterMethodProcessor#writeWithMessageConverters(T, MethodParameter, ServletServerHttpRequest, ServletServerHttpResponse)
// 返回 ModelAndView, 注意这里是 Buffer, 还不是 String 数据
--> RequestMappingHandlerAdapter#getModelAndView
// 获取默认的 视图解析器名称
--> DispatcherServlet#applyDefaultViewName
// 遍历上文获得的 interceptors 数组, 调用各个 HandlerInterceptor 的 postHandle 方法
--> HandlerExecutionChain#applyPostHandle
// 加工结果: 遍历上文获得的 interceptors 数组, 调用各个 HandlerInterceptor 的 afterCompletion 方法
--> DispatcherServlet#processDispatchResult
--> HandlerExecutionChain#triggerAfterCompletion
2.2 WebMvcConfigurationSupport & WebMvcConfigurer
2.2.1 WebMvcConfigurationSupport
2.2.2 WebMvcConfigurer
WebMvcConfigurerAdapter 已废弃.
/**
* @EnableWebMvc 注解驱动的配置类来实现该接口, 从而自定义一些 webmvc 的配置
*/
public interface WebMvcConfigurer {
/**
* 配置 HandlerMappings 路径匹配选项, 比如尾部斜杠匹配, 后缀注册, 路径匹配器和路径助手
* Configured path matcher and path helper instances are shared for:
* RequestMappings, ViewControllerMappings, ResourcesMappings
*/
default void configurePathMatch(PathMatchConfigurer configurer) {}
/**
* Configure content negotiation options. --> 消息体
* 主要是方便一个请求路径返回多个数据格式。
* ContentNegotiationConfigurer这个配置里面你会看到MediaType,里面有众多的格式
*/
default void configureContentNegotiation(ContentNegotiationConfigurer configurer) {}
/**
* Configure asynchronous request handling options.
* 处理异步请求的。只能设置两个值,
* 一个超时时间(毫秒,Tomcat下默认是10000毫秒,即10秒),还有一个是AsyncTaskExecutor,异步任务执行器。
*/
default void configureAsyncSupport(AsyncSupportConfigurer configurer) {}
/**
* 将未被匹配到的 handler 转发至此处进行处理。
* 可以实现静态文件可以像Servlet一样被访问。
*/
default void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {}
/**
* 增加转化器或者格式化器。这边不仅可以把时间转化成你需要时区或者样式。
* 还可以自定义转化器和你数据库做交互,比如传进来userId,经过转化可以拿到user对象。
*/
default void addFormatters(FormatterRegistry registry) {}
/**
* 添加拦截器. 可以拦截所有 controller 请求, 也可以拦截指定格式的URL.若要拦截静态资源:
* 要么声明 MappedInterceptor 对象;
* 要么继承 WebMvcConfigurationSupport 并重写 resourceHandlerMapping 方法.
*/
default void addInterceptors(InterceptorRegistry registry) {}
/**
* 自定义资源映射。添加处理静态资源的 handler 来处理来自 root 路径, classpath, 及其他路径的静态资源:images, js, and, css
* registry.addResourceHandler("/my/**").addResourceLocations("file:E:/my/"); // windows下, 请加上 file:
* super.addResourceHandlers(registry);
*/
default void addResourceHandlers(ResourceHandlerRegistry registry) {}
/**
* 配置跨域请求处理
*/
default void addCorsMappings(CorsRegistry registry) {}
/**
* 配置一个路径自动跳转到另一个路径. 前后分离项目, 可以换种思路处理.
*/
default void addViewControllers(ViewControllerRegistry registry) {}
/**
* 配置视图解析器
*/
default void configureViewResolvers(ViewResolverRegistry registry) {}
/**
* 配置参数解析器
*/
default void addArgumentResolvers(List resolvers) {}
/**
* 配置返回值处理的 handlers
*/
default void addReturnValueHandlers(List handlers) {}
/**
* 配置 MessageConverters, 会覆盖已有的 MessageConverter
*/
default void configureMessageConverters(List> converters) {}
/**
* 配置扩展的 MessageConverter, 不会覆盖已有的 MessageConverter
*/
default void extendMessageConverters(List> converters) {}
/**
* 配置异常解析器
*/
default void configureHandlerExceptionResolvers(List resolvers) {}
/**
* 配置扩展的异常解析器
*/
default void extendHandlerExceptionResolvers(List resolvers) {}
/**
* 提供一个自定义的 Validator 来替代默认的 Validator.
* 默认的实现基于 JSR-303 在 classpath 下, 是: OptionalValidatorFactoryBean.
*/
@Nullable
default Validator getValidator() {
return null;
}
/**
* 提供一个自定义的 MessageCodesResolver 构建来自 data binding 以及 validation 错误码的 消息编码
*/
@Nullable
default MessageCodesResolver getMessageCodesResolver() {
return null;
}
}
2.3 RequestMappingHandlerAdapter
https://www.cnblogs.com/leskang/p/6101368.html (SpringMVC流程参考)
http://www.imooc.com/article/281642?block_id=tuijian_wz (源码分析综合)
https://www.jianshu.com/p/c415f04f61b5 (源码分析--> 已参考)
https://segmentfault.com/a/1190000019448892 (WebMvcConfigurer)
https://www.jianshu.com/p/c5c1503f5367 (WebMvcConfigurationSupport)