springmvc 的请求处理过程(精编)
springmvc 的请求处理过程(精编)
1. DispacherServlet 前端控制器接受发送过来的请求,交给HandlerMapping 处理映射器,
2. HandlerMapping 处理映射器, 根据请求找到相应的HandlerAdapter 处理适配器(处理适配器就是那些拦截器活着吧Controller)
3. HandlerAdapter处理器适配器,处理一些功能请求, 返回一个ModleAndView 对象,包括模型数据、逻辑视图名。
ViewResolver视图解析器 ,先根据ModleAndView 中设置的view 解析具体视图
5. 然后将Modle模型中得数据渲染到View中。
这些过程都是以DispatchServlet 为中轴线进行的。
首先说说:HandlerMapping 视图解析器的接口
作用是根据当前请求的找到对应的Handler 并将Handler(执行程序) 与一对HandlerInterceptor(拦截器)封装到HandlerExecutionChain 对象中。在HandlerMapping接口的内部只有一个方法,如下
- HandlerExecutionChain getHandler(HttpServletRequest request);
HandlerMapping 是由 DispatcherServlet 调用,DispatcherServlet 会从容器中取出所有 HandlerMapping 实例并遍历,让 HandlerMapping 实例根据自己实现类的方式去尝试查找 Handler,而 HandlerMapping 具体有哪些实现类下面就会详细分析。
HandlerMapping 实现类有两个分支,分别继承自 AbstractHandlerMethodMapping(得到 HandlerMethod)和 AbstractUrlHandlerMapping(得到 HttpRequestHandler、Controller 或 Servlet),它们又统一继承于AbstractHandlerMapping。
先来看一下 AbstractHandlerMapping,它实现了 HandlerMapping 接口中的 getHandler() 方法,源码如下所示:
@Override
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
// 根据请求获取执行程序,具体的获取方式由子类决定,getHandlerInternal() 是抽象方法
Object handler = getHandlerInternal(request);
if (handler == null) {
handler = getDefaultHandler();
}
if (handler == null) {
return null;
}
// Bean name or resolved handler?
if (handler instanceof String) {
String handlerName = (String) handler;
handler = getApplicationContext().getBean(handlerName);
}
// 将 Handler 与一堆拦截器包装到 HandlerExecutionChain 对象中
return getHandlerExecutionChain(handler, request);
}
// 将 Handler 与一堆拦截器包装到 HandlerExecutionChain 对象中
可以看到在这个方法中又调用了 getHandlerInternal() 方法获取到了 Handler 对象,而 Handler 对象具体内容是由它的子类去定义的。下面就来一看下 AbstractHandlerMapping 的两个分支子类。
(2):AbstractHandlerMethodMapping
AbstractHandlerMethodMapping 这个分支获取的 Handler 的类型是 HandlerMethod,即这个 Handler 是一个方法,它保存了方法的信息(如Method),这样一个 Controller 就可以处理多个请求了,源码如下所示:
@Override
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
// 根据当前请求获取“查找路径” 从 HttpServletRequest中获取请求的路径。
String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
// 获取当前请求最佳匹配的处理方法(即Controller类的方法中)(获取请求中的方法)
HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
}
下面的是 lookupHandlerMethod(lookupPath, request); 的方法体:
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<AbstractHandlerMethodMapping<T>.Match> matches = new ArrayList();
//根据请的路径找到 直接访问的路径。
List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
if (directPathMatches != null) {
this.addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
this.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
}
if (!matches.isEmpty()) {
Comparator<AbstractHandlerMethodMapping<T>.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
Collections.sort(matches, comparator);
if (this.logger.isTraceEnabled()) {
this.logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches);
}
AbstractHandlerMethodMapping<T>.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (matches.size() > 1) {
if (CorsUtils.isPreFlightRequest(request)) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
AbstractHandlerMethodMapping<T>.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.handlerMethod.getMethod();
Method m2 = secondBestMatch.handlerMethod.getMethod();
throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" + request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
}
}
this.handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.handlerMethod;
} else {
return this.handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
}
}
上述代码中 lookupHandlerMethod() 方法主要工作是在 Map<T, HandlerMethod> handlerMethods 中找到 HandlerMethod,这里的 T 是 HandlerMappingInfo,它封装了 @RequestMapping 注解中的信息。那 HandlerMethod 是怎么创建的(即怎么把 Controller 的方法变成了它),
即: mapping 与handlerMethod(处理方法的)关系;
继续看一下源码找到 initHandlerMethods() 方法,这个方法是在这个类创建后调用的,如下所示是它的源码:
protected void initHandlerMethods() {
// 从容器中获取所有 Bean 的名称,detectHandlerMethodsInAncestorContexts 默认false,不从父容器中查找
//即默认只查找 SpringMVC 的 IOC 容器,不查找它的父容器 Spring 的 IOC 容器
String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
getApplicationContext().getBeanNamesForType(Object.class));
for (String beanName : beanNames) {
// 这里的 isHandler()方法由子类实现,判断是否拥有 @Controller 注解或 @RequestMapping 注解
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(beanName))){
// 利用反射得到 Bean 中的 Method 并包装成 HandlerMethod,然后放入 Map 中
detectHandlerMethods(beanName);
}
}
handlerMethodsInitialized(getHandlerMethods());
}
看完上述代码后,可以知道是在 detectHandlerMethods() 方法中将 Bean 的方法转换为 HandlerMethod 对象,具体实现如下
protected void detectHandlerMethods(final Object handler) {
// 获取这个 Bean 的 Class 对象
Class<?> handlerType = (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());
// 避免重复调用 getMappingForMethod(),getMappingForMethod() 将重新构建 RequestMappingInfo 实例
final Map<Method, T> mappings = new IdentityHashMap<Method, T>();
// 获取被代理前的原始类型
final Class<?> userType = ClassUtils.getUserClass(handlerType);
// 获取 Method
Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
@Override
public boolean matches(Method method) {
// 根据 Method 和它的 @RequestMapping 注解,创建 RequestMappingInfo 对象。
// 这里的 T 就是 RequestMappingInfo,它封装了 @RequestMapping 信息
T mapping = getMappingForMethod(method, userType);
if (mapping != null) {
mappings.put(method, mapping);
return true;
} else {
return false;
}
}
});
for (Method method : methods) {
// 注册 Method 和它的映射,RequestMappingInfo 储存着映射信息
registerHandlerMethod(handler, method, mappings.get(method));
}
}
最后在 registerHandlerMethod() 方法中,将 RequestMappingInfo 作为 key,把 Method 包装成HandlerMethod 作为 value 添加到了 Map<T, HandlerMethod> handlerMethods 中。
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);
HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping);
if (oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {
throw new IllegalStateException("");
}
this.handlerMethods.put(mapping, newHandlerMethod);
Set<String> patterns = getMappingPathPatterns(mapping);
for (String pattern : patterns) {
if (!getPathMatcher().isPattern(pattern)) {
this.urlMap.add(pattern, mapping);
}
}
}
接下来我们接着看看:HandlerAdapter
根据 Handler 来找到支持它的 HandlerAdapter,通过 HandlerAdapter 执行这个 Handler 得到 ModelAndView 对象。HandlerAdapter 接口中的方法如下:
HandlerAdapter的接口的方法:
public interface HandlerAdapter {
boolean supports(Object var1);
ModelAndView handle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;
long getLastModified(HttpServletRequest var1, Object var2);
}
该接口的具体的实现类有:
HttpRequestHandlerAdapter,SimpleControllerHandlerAdapter,AnnotationMethodHandlerAdapter,这个三个类是具体实现HandlerAdapter这个接口的三个类;
1 RequestMappingHandlerAdapter
从上面的文章中可以知道,利用 RequestMappingHandlerMapping 获取的 Handler 是 HadnlerMethod 类型,它代表 Controller 里要执行的方法,而 RequestMappingHandlerAdapter 可以执行 HadnlerMethod 对象。
RequestMappingHandlerAdapter 的 handle()方法是在它的父类 AbstractHandlerMethodAdapter 类中实现的,源码如下所示
@Override public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return handleInternal(request, response, (HandlerMethod) handler); }
handleInternal() 方法是由 RequestMappingHandlerAdapter 自己来实现的,源码如下所示
@Override
protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
// 是否通过 @SessionAttributes 注释声明了 session 属性。
if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
} else {
checkAndPrepare(request, response, true);
}
// 是否需要在 synchronize 块中执行
if (this.synchronizeOnSession) {
HttpSession session = request.getSession(false);
if (session != null) {
Object mutex = WebUtils.getSessionMutex(session);
synchronized (mutex) {
// 执行 HandlerMethod
return invokeHandleMethod(request, response, handlerMethod);
}
}
}
// 执行 HandlerMethod,得到 ModelAndView
return invokeHandleMethod(request, response, handlerMethod);
}
继续再来看一下如何得到 ModelAndView,invokeHandlerMethod() 方法如下
private ModelAndView invokeHandleMethod(HttpServletRequest request,
HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
//
ServletWebRequest webRequest = new ServletWebRequest(request, response);
// 数据绑定
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
// 绑定参数,执行方法
ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
// 创建模型和视图容器
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
// 设置FlasgMap中的值
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
// 初始化模型
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
asyncWebRequest.setTimeout(this.asyncRequestTimeout);
final 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();
requestMappingMethod = requestMappingMethod.wrapConcurrentResult(result);
}
requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
if (asyncManager.isConcurrentHandlingStarted()) {
return null;
}
return getModelAndView(mavContainer, modelFactory, webRequest);
}
2 HttpRequestHandlerAdapter
HttpRequestHandlerAdapter 可以执行 HttpRequestHandler 类型的 Handler,源码如下
@Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((HttpRequestHandler) handler).handleRequest(request, response); return null; }
3 SimpleControllerHandlerAdapter
SimpleControllerHandlerAdapter 可以执行 Controller 类型的 Handler,源码如下
@Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response); }
4 SimpleServletHandlerAdapter
SimpleServletHandlerAdapter 可以执行 Servlet 类型的 Handler,源码如下
@Override public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { ((Servlet) handler).service(request, response); return null; }
ModelAndView resolveException(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex);
转载于:https://www.cnblogs.com/wangdong811/p/10300247.html
springmvc 的请求处理过程(精编)相关推荐
- 面试官:小伙汁,你画的SpringMVC请求处理过程是从网上抄的吧?
点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 作者:Sicimike blog.csdn.net/Bai ...
- 小手取红色球C语言程序,C语言程序设计例精编.doc
C语言程序设计例精编 C语言程序设计案例精编 C语言程序设计案例精编.txt"我羡慕内些老人羡慕他们手牵手一直走到最后.━交话费的时候,才发现自己的话那么值钱.案例一 贪吃蛇游戏 #defi ...
- 城镇开发边界划定指南_URP精编 | 基于 “双评价”的城镇开发边界划定实证研究...
致读者 URP今日为您精编的是罗伟玲.吴欣昕.刘小平.张大川.刘鹏华与何家律的<基于 "双评价"的城镇开发边界划定实证研究>,感谢罗伟玲老师提供的精编版.若您想了解更多 ...
- c语言游戏经典案例,C语言_编游戏案例精编.doc
C语言_编游戏案例精编 C语言_编游戏案例精编 C语言 编游戏案例精编 案例一 贪吃蛇游戏 案例二 计算器 案例三 黑白棋游戏 案例四 迷宫问题 案例五 扫地雷游戏 案例六 速算24 案例七 数据结构 ...
- Oracle 精编实用手册
<Oracle精编实用手册> by Else 序章 第1章 Oracle 基础概念 1.1 数据库简介 1.2 Oracle 简介 第2章 Oracle 建立和介绍 2.1 Oracle ...
- 《中国人工智能系列白皮书——智能驾驶》精编
[转] https://www.leiphone.com/news/201710/x7tHyZS8lsohsatP.html 10月12日,中国人工智能学会发布中国人工智能系列白皮书,雷锋网作为邀请媒 ...
- C专家编程 精编之一
C专家编程 精编之一 第一章~第三章 C的复杂之处 在于它的指针 ,但是比其指针更为复杂的是它的声明 !!! 你能看懂它们的意思 吗? apple=sizeof(int)*p ; ap ...
- Golang精编100题-搞定golang面试
Golang精编100题 能力模型 级别 模型 初级 primary 熟悉基本语法,能够看懂代码的意图: 在他人指导下能够完成用户故事的开发,编写的代码符合CleanCode规范: 中级 interm ...
- x小学计算机知识竞赛方案,竞赛方案精编小学竞赛方案
小学可以开展的竞赛活动多种多样,以下是小编精心收集整理的小学竞赛活动,下面小编就和大家分享,来欣赏一下吧. 小学竞赛活动1 一.活动主题 思考,让生活更美好. 二.活动目的 1.通过这次活动,让更多同 ...
最新文章
- 2021美国科学天才奖发榜!16名华裔高中生入围「少年诺奖」
- poj-2406(kmp水题)
- mongodb--常用命令
- c#精彩编程200例百度云_永安市教育局被授予“人工智能编程教育试验区”
- 前端学习(1296):第三方模块nodenrm
- Spring AOP 五大通知类型
- python遗传算法计算实例_遗传算法python简单例子(详解)
- 福利 | 闷骚的程序员是如何讲冷笑话的?
- Java 多线程 - 线程 - 守护线程
- 随着公网对讲机市场占有率得不断增长,部分对讲机厂家为了得到用户的认可,不断升级对讲机及时以及对讲机的功能和性能,因此越来越多的全国对讲机以及公网对讲机问世。但是某些用户不清楚对讲机的原理,不禁会问
- 低通滤波器转带通滤波器公式由来_无源滤波器应用或电路中的带通滤波器原理...
- 不能被编辑的html文档,word不能编辑怎么办 Word文档怎么设置成不可编辑?
- thinkpad T580加装内存条
- matlab中迪杰斯特拉算法,dijkstra算法(迪杰斯特拉算法)
- 网络工程师需要学c语言,网络工程师需要学哪些内容
- python后缀是什么_python文件的后缀名是什么
- 抖音,B站,小红书三大平台品牌投放特征与建议
- 远程IO模块16DO开关量输出采集远程模块
- MAC 在线安装系统
- HDU6608 Fansblog
热门文章
- 蓝桥杯 ADV-135 算法提高 三角形面积
- 【iOS开发】使用XCode 10添加Launch Image(启动图片)
- LeetCode199. Binary Tree Right Side View
- python连接数据库oracle_python 连接oracle数据库:cx_Oracle
- zabbix--从入门到精通之zabbix历史数据
- Java 程序连接 Informix 数据库方法实例介绍
- Flutter快速上车之Widget 1
- 自己动手写DB数据库框架(增)
- Centos 6中模拟破坏MBR救援模式下修复
- 编译安装Nginx-1.0.1