盘点 SpringMVC : MVC 主流程
总文档 :文章目录
Github : github.com/black-ant
一 . 前言
文章目标 :
- 梳理 SpringMVC 主流程中的相关逻辑
- 确定 相关流程得参数
本文章未涉及的部分:
- MVC 的配置
- 容器的初始化
- 容器的加载
- 等…
二 . 流程分析
此主要流程包括如下几个部分 :
- 注解的扫描处理
- 请求的拦截
- 请求的转换
- 请求的最终处理
2.1 注解的扫描处理
注解的扫描主要在 DispatcherServlet.initHandlerMappings 中 , 其逻辑处理类在 AbstractHandlerMethodMapping.getHandlerInternal 中.
2.1.1 注解的扫描
注解扫描的起点主要是 RequestMappingHandlerMapping , 其中做了这几件事 :
- 在 AbstractHandlerMethodMapping 中通过 InitializingBean 的 afterPropertiesSet 处理所有的方法
- detectHandlerMethods 中进行核心的处理
- 对 RequestMapping 进行了扫描操作 , 并且生成 RequestMappingInfo
C31- RequestMappingHandlerMapping : 扫描的起点 , 因为类实现了 InitializingBean 接口 , 其核心基于 afterPropertiesSet
M- afterPropertiesSet
?- 这个方法中主要对 RequestMappingInfo.BuilderConfiguration 进行配置 ,最后调用父类 afterPropertiesSet 方法
C32- AbstractHandlerMethodMapping
M32_01- afterPropertiesSet
- initHandlerMethods() : 核心方法 , 对 Handler Method 进行处理 -> M32_02
M32_02- initHandlerMethods
?- 扫描ApplicationContext中的bean,检测和注册处理程序方法
- 获取所有的 BeanName , 调用 processCandidateBean 执行 -> M32_03
M32_03- processCandidateBean
- obtainApplicationContext().getType 获取具体的 Class 类
- 通过 isHandler 判断是否包含 Controller 或者 RequestMapping
?- RestController 继承了 Controller
- 如果需要处理 , 调用 detectHandlerMethods 处理 -> M32_04
M32_04- detectHandlerMethods
- 同样的 , 通过传入的 handle (类的别名) 获取对应的 Class<?>
- 获取所有的标注了注解的集合 Map<Method, T> -> ps:M32_04_01
- getMappingForMethod 获取注解对应的 Condition -> ps:M32_04_01 详细流程
- selectMethods
FOR- 循环所有的 methods , 首先搜索可用的代理 , 注册对应的 Bean
?- 代理是 Spring 中很重要的一环 , 后面开单章详细说
M32_05- registerHandlerMethod
- 注册到 MappingRegistry
// ps:M32_04_01 流程详细分析
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,(MethodIntrospector.MetadataLookup<T>) method -> {
return getMappingForMethod(method, userType);
});
// 可以看到 , 其中核心的方法有2个 getMappingForMethod / selectMethods
getMappingForMethod 会返回Mapping 对应的 Condition , 例如 patternsCondition / methodCondition
// ps:M32_04_01
protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
// 此处对 RequestMapping 进行了扫描操作
// 代码比较简单 , 就是 AnnotatedElementUtils.findMergedAnnotation 后构建了一个 RequestMappingInfo bean
RequestMappingInfo info = createRequestMappingInfo(method);
if (info != null) {
// 此处是获取 Class 类上面的 RequestMapping
RequestMappingInfo typeInfo = createRequestMappingInfo(handlerType);
if (typeInfo != null) {
// 对2者进行组合 , 生成新的 Bean 对象
// 注意是类 组合 方法
// 主要是覆盖和合并 , url 比较特殊 , 变化为 /get -> /cookie/get
info = typeInfo.combine(info);
}
// 前缀 path 的处理 , 该属性在配置 PathMatchConfigurer 时处理 , 可以通过 addPathPrefix 添加
String prefix = getPathPrefix(handlerType);
if (prefix != null) {
info = RequestMappingInfo.paths(prefix).options(this.config).build().combine(info);
}
}
return info;
}
复制代码
2.1.2 Bean 的注册
上面的环节已经对 Mapping Method 扫描完成 , 在此环节中进行注册 , 注册主要使用内部类MappingRegistry , 其内部存在多个 Map ,用于保存地址的映射关系
(url -MappingRegistration/HandlerMethod/CorsConfiguration 等 )
C- AbstractHandlerMethodMapping
VC33- MappingRegistry : 内部类
F33_01- Map<T, MappingRegistration<T>> registry = new HashMap<>();
F33_02- Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
F33_03- MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
F33_04- Map<String, List<HandlerMethod>> nameLookup = new ConcurrentHashMap<>();
F33_05- Map<HandlerMethod, CorsConfiguration> corsLookup = new ConcurrentHashMap<>();
M33_01- register(T mapping, Object handler, Method method) -> PS:M33_01
?- 此处主要是为了构建 Map 集合 , 用于映射时匹配
1- 通过 handler 和 Method 构建了使用时的主要单元Bean HandlerMethod
2- 以 RequestMappingInfo(mapping) 为key 将 HandlerMethod 放入 Map (F33_02) 集合
3- 以 URL 字符串为 key , 将 以 RequestMappingInfo(mapping) 放入 Map 集合 (F33_03)
4- 以 Name (策略类构建特殊的 mappingName)为 key , 将 handlerMethod 放入 Map (F33_04) -> PS:M33_02
5- 以 HandlerMethod 为 key , 将 CorsConfiguration 放入集合 Map (F33_05)
6- 以 RequestMappingInfo(mapping) 为key , 生成一个 MappingRegistration 放入集合 registry (F33_01)
// PS:M33_01 register 方法的关键和亮点
1- 使用 ReentrantReadWriteLock 保证多线程下访问的唯一性 , 在 finally 中解锁
// PS:M33_02 特殊的命名方式 RequestMappingInfoHandlerMethodMappingNamingStrategy
这里主要通过 RequestMappingInfoHandlerMethodMappingNamingStrategy 类生成对应的 Name
// M33_01 伪代码
public void register(T mapping, Object handler, Method method) {
this.readWriteLock.writeLock().lock();
try {
// 1- 通过 handler 和 Method 构建了使用时的主要单元Bean HandlerMethod
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
validateMethodMapping(handlerMethod, mapping);
// 2- 以 RequestMappingInfo(mapping) 为key 将 HandlerMethod 放入 Map (F33_02) 集合
this.mappingLookup.put(mapping, handlerMethod);
List<String> directUrls = getDirectUrls(mapping);
for (String url : directUrls) {
// 3- 以 URL 字符串为 key , 将 以 RequestMappingInfo(mapping) 放入 Map 集合 (F33_03)
this.urlLookup.add(url, mapping);
}
String name = null;
if (getNamingStrategy() != null) {
name = getNamingStrategy().getName(handlerMethod, mapping);
// 4- 以 Name (策略类构建特殊的 mappingName)为 key , 将 handlerMethod 放入 Map (F33_04)
addMappingName(name, handlerMethod);
}
// 构建跨域配置
CorsConfiguration corsConfig = initCorsConfiguration(handler, method, mapping);
if (corsConfig != null) {
5- 以 HandlerMethod 为 key , 将 CorsConfiguration 放入集合 Map (F33_05)
this.corsLookup.put(handlerMethod, corsConfig);
}
// 6- 以 RequestMappingInfo(mapping) 为key , 生成一个 MappingRegistration 放入集合 registry
this.registry.put(mapping, new MappingRegistration<>(mapping, handlerMethod, directUrls, name));
}finally {
this.readWriteLock.writeLock().unlock();
}
}
// 自此 , Mapper 的前期准备就完成了
复制代码
2.2 请求的来临
请求的入口还是通过 Servlet 来完成的 , 先看一下 Servlet 体系 PS:51_01
2.2.1 起点 : 初始化一个 Servlet
MVC 是基于 Servlet 的体系结构 , 其最初的起点是通过 StandardWrapper 进行 initServlet 开始 流转路径如下 :
StandardWrapper -> GenericServlet (init) -> HttpServletBean (init) -> FrameworkServlet (initServletBean)
复制代码
看一个很老的图 , 大概对 DispatcherServlet 有个初步的了解 :
2.2.2 核心 : DispatchServlet 的初始化
C51- DispatcherServlet
M51_10- initHandlerMappings(ApplicationContext context)
?- 这个方法的核心操作就是初始化 handlerMappings -> PS:M51_10_01
- 通过 BeanFactoryUtils 构建所有的 Mapping 类型结合
- 为 Map 进行排序
复制代码
Filter 处理逻辑 , Filter 分为 3步 : 初始化 , 拦截 , 销毁 , 此处主要是初始化操作 >>
Filter 不是 Spring 专属的对象 , 其归属于 Servlet 原生体系 , 主要有以下2个流程
子流程一 : 核心处理容器 : StandardContext,添加 Filter 流程
- ServletWebServerApplicationContext # selfInitialize : 获取所有的需要处理的 Filter 类
- ServletContextInitializerBeans # ServletContextInitializerBeans : 从 Factory 中获取具体的类
- RegistrationBean # onStartup : 启动 并且注册 FilterBean
- StandardContext # addFilterDef : 添加 FilterDef , 即 filter definition
C- ServletWebServerApplicationContext
M- selfInitialize
- getServletContextInitializerBeans 其中会获取所有的 Beans , 分别调用 beans.onStartup 启动
M- getServletContextInitializerBeans
- 核心处理逻辑在 ServletContextInitializerBeans 中
C- ServletContextInitializerBeans
M- ServletContextInitializerBeans(ListableBeanFactory beanFactory,Class<? extends ServletContextInitializer>... initializerTypes)
?- 此方法中会获取 Servlet 和 Filter 的初始化类 --> TODO : 后续单独分析 Serlvet 时看
复制代码
子流程二 : 调用 Filter 初始化流程
这是一个异步操作 : 通过一个 call 流程异步处理 , 具体的流程在 org.apache.catalina.core 中
- StandardContext # filterStart : Set filterDefs.entrySet 中获取所有的 Filter
- ApplicationFilterConfig : 构建一个 ApplicationFilterConfig 并且在其中调用 initFilter() 初始化
// Filter 的拦截调用
Filter 的核心思路就是 FilterChain 的链表调用 . 其起点为 ApplicationFilterChain
C- ApplicationFilterChain
F- private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
- 选择一个 ApplicationFilterConfig , 调用 doFilter , 并且把当前对象传入
?- 后续就是调用链的逻辑
// HandlerInterceptor 的处理流程
- 与 Filter 不同的是 , 这里的 HandlerInterceptor 是 Spring 体系中的对象
- 拦截器主要在 WebMvcConfigurer 通过 InterceptorRegistry 手动注入
@Override
public void addInterceptors(InterceptorRegistry registry) {
logger.info("------> this is addInterceptors <-------");
registry.addInterceptor(new ConfigInterceptor());
}
// Interceptor 的初始化
Interceptor 的主要起点是 WebMvcConfigurationSupport
C- WebMvcConfigurationSupport
M- requestMappingHandlerMapping
- 其中会为当前 Mapping 添加 Interceptor
// Interceptor 的调用
Interceptor 的主调流程位于 HandlerExecutionChain
C- HandlerExecutionChain
M- applyPreHandle
- getInterceptors() 获取 HandlerInterceptor->LV001 数组
FOR- 循环 HandlerInterceptor:LV001 调用 preHandle
// DispatcherServlet 衔接到 RequestMapping 映射关联
- ApplicationFilterChain 处理完成 Filter
// 这里会进行一次继承类的循环调用
C- DispatcherServlet
M- FrameworkServlet
M- HttpServlet
- HttpServlet 执行 service(ServletRequest req, ServletResponse res) 方法
- FrameworkServlet 执行 service(HttpServletRequest request, HttpServletResponse response) 方法
- HttpServlet 执行 service(HttpServletRequest request, HttpServletResponse response) 方法
- FrameworkServlet 执行 doGet 处理请求
- FrameworkServlet 执行 processRequest 开始完整处理
- 来到具体实现类 DispatcherServlet
复制代码
PS:51_01 Servlet 家族体系
PS:M51_10_01 HandlerMapping 家族体系
2.3 请求的解析
servlet 的起始方法是 HttpServlet , Spring 部分的核心方法是实现类FrameworkServlet
解析前置处理操作
- 在 Reuqest 和 Response 转换为 HttpServletRequest 和 HttpServletResponse 后
- 调用 HttpServlet 中 service(HttpServletRequest req, HttpServletResponse resp) 方法 , 触发 FrameworkServlet doGet 方法
- 最终进入 DispatcherServlet 核心类 , 处理一个 Http 请求
2.3.1 DispatcherServlet 获取处理 Handler
Start -> HttpServlet
// TODO : Dispatch 具体流程以后单独分析 , 这里先简单过一下
C51- DispatcherServlet
M51_01- doService(HttpServletRequest request, HttpServletResponse response)
?- 执行 Service 处理请求
- 调用 M51_02 执行具体的流程
M51_02- doDispatch(HttpServletRequest request, HttpServletResponse response)
1- WebAsyncUtils.getAsyncManager(request) : 准备异步处理管理器 WebAsyncManager -> PS:M51_02_01
2- checkMultipart(request) : 尝试解析 Multipart Request -> PS:M51_02_02
3- getHandler(processedRequest) : 获取具体需要执行的 Handler -> M51_03
?- 未找到对应的 Handler 会直接 return
4- getHandlerAdapter(mappedHandler.getHandler()) : 确定当前请求的处理程序适配器 -> PS:M51_02_04
5- 处理 Get-Head 请求 -> PS:M51_02_05
- mappedHandler.applyPreHandle : 前置处理
6- 调用 HandlerAdapter 处理 请求
7- applyDefaultViewName : view 名称的解析 , 此环节不分析
- mappedHandler.applyPostHandle : 后置处理 -> PS:M51_02_09
M51_03- getHandler
M51_04- getHandlerAdapter
// M51_03 源代码
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;
}
// M51_04 getHandlerAdapter 源代码
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if (this.handlerAdapters != null) {
for (HandlerAdapter adapter : this.handlerAdapters) {
// 太常见的处理方式 , 循环处理中通过 support 判断
if (adapter.supports(handler)) {
return adapter;
}
}
}
throw new ServletException("....");
}
复制代码
PS:M51_02_01 WebAsyncManager 介绍
- 作用 : 用于管理异步请求处理的中心类,主要用作SPI,通常不被应用程序类直接使用
- 核心 : 通过多个不同的线程 , 处理请求和结果
- 流程
- 异步场景以线程(T1)中正常的请求处理开始
- 并发请求处理可以通过调用startCallableProcessing或startDeferredResultProcessing来启动,这两种方法都会在单独的线程(T2)中产生一个结果。
- 保存结果并将请求分发给容器,以便在第三个线程(T3)中继续处理保存的结果。
- 在已分派线程(T3)中,可以通过getConcurrentResult()访问保存的结果,或者通过hasConcurrentResult()检测其是否存在。
PS:M51_02_02 : checkMultipart 的目的
为什么这里需要校验一下 checkMultipart ? 其底层主要做了如下几件事 :
- 判断是否有 multipartResolver 并且用该解析器判断是否为Multipart
- 如果以上条件达成 , multipartResolver.resolveMultipart(request) 进行解析返回新 Request
- 否则返回原有 request
说白了 , 就是 multipart request 的处理 , 但是相对的问题又来了 >>> 什么是 multipart request ?
作用 : HTTP 多部分请求是 HTTP 客户机构造的 HTTP 请求,用于将文件和数据发送到 HTTP 服务器。
场景 : 浏览器和 HTTP 客户端通常使用它将文件上传到服务器。
PS:M51_02_04 getHandler 和 getHandlerAdapter 的区别 ?
getHandler -> HandlerExecutionChain
getHandlerAdapter -> HandlerAdapter
// HandlerExecutionChain 的作用 :
- HandlerExecutionChain 是 Handler 的处理器链 , 其中包含了 HandlerInterceptor 的数组和对应的 Handler
// HandlerAdapter 的作用 :
- 首先 , 看名字就知道 , 这是个适配器 , 适配器能在原有功能上扩展新的功能
- MVC框架SPI,允许参数化核心MVC工作流 , 该接口用于允许DispatcherServlet无限扩展。
- DispatcherServlet通过这个接口访问所有已安装的处理程序
复制代码
PS:M51_02_05 GET/HEAD 请求细说
这地方老有意思了 ,刚接触代码那会这里出问题想了好久才知道有这么个东西
参考文档 @ www.cnblogs.com/longyongzhe…
特点 : HEAD方法跟GET方法相同,只不过服务器响应时不会返回消息体。一个HEAD请求的响应中,HTTP头中包含的元信息应该和一个GET请求的响应消息相同。这种方法可以用来获取请求中隐含的元信息,而不用传输实体本身。也经常用来测试超链接的有效性、可用性和最近的修改。
作用 :
- 只请求资源的首部;
- 检查超链接的有效性;
- 检查网页是否被修改;
- 多用于自动搜索机器人获取网页的标志信息,获取rss种子信息,或者传递安全认证信息等
PS:M51_02_09 前置处理和后置处理主要处理什么 ?
- mappedHandler.applyPreHandle : 前置处理
- mappedHandler.applyPostHandle : 后置处理
// 这2个方法主要是对拦截器的处理 , 可以看到其中直接调用拦截器的方法
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;
}
复制代码
M51_02 : DispatcherServlet # doDispatch 源码
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
// 准备异步处理管理器 WebAsyncManager
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
ModelAndView mv = null;
Exception dispatchException = null;
try {
// 尝试解析 Multipart Request
processedRequest = checkMultipart(request);
multipartRequestParsed = (processedRequest != request);
// 获取具体需要执行的 Handler
mappedHandler = getHandler(processedRequest);
if (mappedHandler == null) {
noHandlerFound(processedRequest, response);
return;
}
// 确定当前请求的处理程序适配器
HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
// 处理 Get-Head 请求
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;
}
// 调用 HandlerAdapter 处理 请求
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);
}
}
}
}
复制代码
2.3.2 HandlerMapping 解析到方法
上文中已经获取到了 Adapter , 以下就是 Adapter 的详细处理
流程处理
流程处理分为2个部分 , 简单点说就是 :
- getHandler 获取使用的 MethodHandler
- getHandlerAdapter 获取适配处理器
- 通过适配处理器处理 MethodHandler
一 : 获取处理的 Handler (getHandler)
DispatcherServlet # M51_03- getHandler 中可以看到 , 通过 HandlerExecutionChain # getHandler 获取 Handler 对象
C76- AbstractHandlerMapping
M76_01- HandlerExecutionChain getHandler(HttpServletRequest request) : 构建处理链
- getHandlerInternal(request) 获取处理的 Handler -> M32_01
- 通过 Handler 构建 HandlerExecutionChain TODO
- 跨域配置的处理 CorsConfiguration
M76_02- getHandlerInternal
- 调用 父类 -> M32_01
C32- AbstractHandlerMethodMapping
M32_01- getHandlerInternal(HttpServletRequest request)
- 先配置了一个读锁
- 调用 lookupHandlerMethod -> M32_02
M32_02- lookupHandlerMethod : 对请求做真正的处理 , 获取 HandlerMethod
1- 构建 List<Match> 用于存放匹配结果
- MappingRegistry 通过 lookupPath 获取对象 List<RequestMappingInfo>
?- 底层实际上是调用上文初始化使用的 urlLookup.get(urlPath)
- 调用 addMatchingMappings , 将匹配的 Match放入 1 步构建的 List 中
- 返回处理的 Method
复制代码
M32_02 lookupHandlerMethod 请求处理
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<Match> matches = new ArrayList<>();
// 从 MappingRegistry 中获取 Mapping List
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
// No choice but to go through all mappings...
addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
// 如果匹配项不为空
if (!matches.isEmpty()) {
// {POST /test/getBody}
Match bestMatch = matches.get(0);
// 进行匹配 , 获取对应的 HandlerMethod
if (matches.size() > 1) {
Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
matches.sort(comparator);
bestMatch = matches.get(0);
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
Match secondBestMatch = matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException(
"Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
// request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath) -> PS:M32_02_01
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.handlerMethod);
handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
}
else {
return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
// PS:M32_02_01
String PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE = HandlerMapping.class.getName() + ".pathWithinHandlerMapping";
复制代码
步骤二 : 使用获取的 Handler (HandlerAdapter.handle)
从步骤一中我们已经获取到了 HandleMethod , 后续就是相关的处理逻辑
- DispatcherServlet # doDispatch : 请求入口
- AbstractHandlerMethodAdapter # handle : RequestMappingAdapter 的父入口
- RequestMappingHandlerAdapter # handleInternal :请求处理主流程
- RequestMappingHandlerAdapter # invokeHandlerMethod
- ServletInvocableHandlerMethod # invokeAndHandle
- InvocableHandlerMethod # invokeForRequest
- InvocableHandlerMethod # doInvoke
- Method # invoke : Java 反射到方法
步骤2-1 : RequestMappingHandlerAdapter # handleInternal 处理
在该方法中 , 如果需要视图解析,则调用准备ModelAndView的RequestMapping处理程序方法
核心 : ModelAndView 的准备
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
ServletWebRequest webRequest = new ServletWebRequest(request, response);
try {
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 扩展InvocableHandlerMethod,通过注册的HandlerMethodReturnValueHandler处理返回值
ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
if (this.argumentResolvers != null) {
invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
}
if (this.returnValueHandlers != null) {
invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
}
invocableMethod.setDataBinderFactory(binderFactory);
invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
// ModuleAndView 容器
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, invocableMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.setTaskExecutor(this.taskExecutor);
asyncManager.setAsyncWebRequest(asyncWebRequest);
// 异步管理器注册回调拦截器
asyncManager.registerCallableInterceptors(this.callableInterceptors);
asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);
if (asyncManager.hasConcurrentResult()) {
Object result = asyncManager.getConcurrentResult();
mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
asyncManager.clearConcurrentResult();
invocableMethod = invocableMethod.wrapConcurrentResult(result);
}
invocableMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
finally {
webRequest.requestCompleted();
}
}
复制代码
ModelAndViewContainer 参数详情 :
// Web 模块最终步骤
C- InvocableHandlerMethod
// 代码最终步骤 : 调用 Method 的 invoke 方法 , 去完成具体的逻辑
C39- Method
M39_01- invoke(Object obj, Object... args)
?- 通过此方法调用最后的代理类 . java 反射包中方法 ,省略
复制代码
2.4 补充 : 属性的转换
属性转换的主要类是 RequestMappingHandlerAdapter , 其主要调用逻辑为 :
- C90- RequestMappingHandlerAdapter # M90_1- invokeHandlerMethod
- C91- ServletInvocableHandlerMethod # M91_1- invokeAndHandle
- C92- InvocableHandlerMethod # M92_1- invokeForRequest : 对请求进行处理
- C93- InvocableHandlerMethod # M93_1- getMethodArgumentValues : 获取参数
- C94- HandlerMethodArgumentResolverComposite # M94_1- resolveArgument : 解析参数
- C95- RequestResponseBodyMethodProcessor # M95_1- readWithMessageConverters : 转换参数
- C96- AbstractMessageConverterMethodArgumentResolver # M96_1- readWithMessageConverters : 最终处理逻辑
C- RequestMappingHandlerAdapter
M- invokeHandlerMethod(HttpServletRequest request,HttpServletResponse response, HandlerMethod handlerMethod)
- invocableMethod.invokeAndHandle(webRequest, mavContainer)
// Step 1 : 处理的入口
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
// 将 Request 解析处理
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception ex) {
throw ex;
}
}
// PS : invokeForRequest 中主要流程
C- InvocableHandlerMethod
M- invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,Object... providedArgs)
- getMethodArgumentValues(request, mavContainer, providedArgs)
?- 详见下文参数获取
复制代码
Step 2 : 参数的获取
protected Object[] getMethodArgumentValues(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
MethodParameter[] parameters = getMethodParameters();
if (ObjectUtils.isEmpty(parameters)) {
return EMPTY_ARGS;
}
// 构建一个 Object 数组用于存放 param
Object[] args = new Object[parameters.length];
for (int i = 0; i < parameters.length; i++) {
MethodParameter parameter = parameters[i];
parameter.initParameterNameDiscovery(this.parameterNameDiscoverer);
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
if (!this.resolvers.supportsParameter(parameter)) {
throw new IllegalStateException(formatArgumentError(parameter, "No suitable resolver"));
}
try {
// 解析参数主体
args[i] = this.resolvers.resolveArgument(parameter, mavContainer, request, this.dataBinderFactory);
}
catch (Exception ex) {
throw ex;
}
}
return args;
}
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
HandlerMethodArgumentResolver resolver = getArgumentResolver(parameter);
if (resolver == null) {
throw new IllegalArgumentException("Unsupported parameter type [" +
parameter.getParameterType().getName() + "]. supportsParameter should be called first.");
}
return resolver.resolveArgument(parameter, mavContainer, webRequest, binderFactory);
}
复制代码
Step 3 : RequestResponseBodyMethodProcessor 解析 RequestBody
public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer,
NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception {
parameter = parameter.nestedIfOptional();
// 读取并且转换为相关对象
Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType());
String name = Conventions.getVariableNameForParameter(parameter);
if (binderFactory != null) {
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());
}
}
if (mavContainer != null) {
mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
}
}
return adaptArgumentIfNecessary(arg, parameter);
}
// Step : 转换操作入口
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter,
Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest);
Object arg = readWithMessageConverters(inputMessage, parameter, paramType);
if (arg == null && checkRequired(parameter)) {
throw new HttpMessageNotReadableException("Required request body is missing: " +
parameter.getExecutable().toGenericString(), inputMessage);
}
return arg;
}
复制代码
Step end : 最终处理
最终处理中, 对 属性参数进行了最后的映射
PS: M96_1_01 继承体系
- C- EmptyBodyCheckingHttpInputMessage
- C- HttpInputMessage
- C- HttpMessage
PS:M96_01_02 , 所有的 MessageConverter
- ByteArrayHttpMessageConverter
- StringHttpMessageConverter
- ResourceHttpMessageConverter
- ResourceRegionHttpMessageConverter
- SourceHttpMessageConverter
- AllEncompassingFormHttpMessageConverter
- Jaxb2RootElementHttpMessageConverter
- MappingJackson2HttpMessageConverter
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
MediaType contentType;
boolean noContentType = false;
try {
// 内容类型 : application/json;charset=UTF-8
contentType = inputMessage.getHeaders().getContentType();
} catch (InvalidMediaTypeException ex) {
throw new HttpMediaTypeNotSupportedException(ex.getMessage());
}
if (contentType == null) {
noContentType = true;
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
// Controller 类
Class<?> contextClass = parameter.getContainingClass();
// 实体类 class
Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
if (targetClass == null) {
ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
targetClass = (Class<T>) resolvableType.resolve();
}
// 获取请求类型
HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
Object body = NO_VALUE;
EmptyBodyCheckingHttpInputMessage message;
try {
// PS: M96_1_01
message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
// 获取所有的 HttpMessageConverter -> PS:M96_01_02
for (HttpMessageConverter<?> converter : this.messageConverters) {
Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
GenericHttpMessageConverter<?> genericConverter =
(converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
// 此处主要是 MappingJackson2HttpMessageConverter
if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
(targetClass != null && converter.canRead(targetClass, contentType))) {
if (message.hasBody()) {
// 转换核心流程 -> PS:M96_01_02
// 主要为 Header
HttpInputMessage msgToUse =
getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
} else {
body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
}
break;
}
}
} catch (IOException ex) {
throw new HttpMessageNotReadableException("I/O error while reading input message", ex, inputMessage);
}
if (body == NO_VALUE) {
if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||(noContentType && !message.hasBody())) {
return null;
}
throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
}
MediaType selectedContentType = contentType;
Object theBody = body;
LogFormatUtils.traceDebug(logger, traceOn -> {
String formatted = LogFormatUtils.formatValue(theBody, !traceOn);
return "Read \"" + selectedContentType + "\" to [" + formatted + "]";
});
return body;
}
复制代码
PS:M96_01_02 参数详情
2.5 补充 : Response 的转换
属性的转换主要在 HandlerMethodReturnValueHandlerComposite 中进行 , 主要的逻辑为 :
- C- InvocableHandlerMethod # invokeForRequest
- C- ServletInvocableHandlerMethod # invokeAndHandle
- C- HandlerMethodReturnValueHandlerComposite # handleReturnValue : 调用 Handler 处理
- C- RequestResponseBodyMethodProcessor # handleReturnValue
// - C91- ServletInvocableHandlerMethod # M91_1- invokeAndHandle
public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
Object... providedArgs) throws Exception {
Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
setResponseStatus(webRequest);
if (returnValue == null) {
if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
disableContentCachingIfNecessary(webRequest);
mavContainer.setRequestHandled(true);
return;
}
} else if (StringUtils.hasText(getResponseStatusReason())) {
mavContainer.setRequestHandled(true);
return;
}
mavContainer.setRequestHandled(false);
try {
// 此处进行 return 处理 : HandlerMethodReturnValueHandlerComposite
this.returnValueHandlers.handleReturnValue(
returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
} catch (Exception ex) {
throw ex;
}
}
// HandlerMethodReturnValueHandlerComposite # handleReturnValue
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
if (handler == null) {
throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
}
handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
// RequestResponseBodyMethodProcessor
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
mavContainer.setRequestHandled(true);
ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);
// 此处进行返回处理 , 本次先不深入 , 以后单独看看返回的处理
writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
}
复制代码
总结
总算是把 MVC 写完了 , 本来篇幅不大 ,结果越写越多 , 反而不容易说清楚了.
说的太多容易影响清晰度 , 其中有一些环节没详细说 , 后续在单独的小篇详细说说
作者:AntBlack
链接:https://juejin.cn/post/6965845173691482148
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
共同学习,写下你的评论
评论加载中...
作者其他优质文章