浅谈SpringMVC请求映射handler源码解读
作者:是冯吉荣呀 发布时间:2022-09-11 14:37:36
请求映射源码
首先看一张请求完整流转图(这里感谢博客园上这位大神的图,博客地址我忘记了):
前台发送给后台的访问请求是如何找到对应的控制器映射并执行后续的后台操作呢,其核心为DispatcherServlet.java与HandlerMapper。在spring boot初始化的时候,将会加载所有的请求与对应的处理器映射为HandlerMapper组件。我们可以在springMVC的自动配置类中找到对应的Bean。
@Bean
@Primary
@Override
public RequestMappingHandlerMapping requestMappingHandlerMapping(
@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,
@Qualifier("mvcConversionService") FormattingConversionService conversionService,
@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {
// Must be @Primary for MvcUriComponentsBuilder to work
return super.requestMappingHandlerMapping(contentNegotiationManager, conversionService,
resourceUrlProvider);
}
@Bean
public WelcomePageHandlerMapping welcomePageHandlerMapping(ApplicationContext applicationContext,
FormattingConversionService mvcConversionService, ResourceUrlProvider mvcResourceUrlProvider) {
WelcomePageHandlerMapping welcomePageHandlerMapping = new WelcomePageHandlerMapping(
new TemplateAvailabilityProviders(applicationContext), applicationContext, getWelcomePage(),
this.mvcProperties.getStaticPathPattern());
welcomePageHandlerMapping.setInterceptors(getInterceptors(mvcConversionService, mvcResourceUrlProvider));
welcomePageHandlerMapping.setCorsConfigurations(getCorsConfigurations());
return welcomePageHandlerMapping;
}
请求将首先执行FrameworkServlet
下的service方法根据request请求的method找到对应的do**方法。
@Override
protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
processRequest(request, response);
}
else {
//父类根据method参数执行doGet,doPost,doDelete等
super.service(request, response);
}
}
而这些do**其都会进入核心方法,以doGet为例。
@Overrideprotected
final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//核心方法
processRequest(request, response);
}
protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
try {
//进入此核心方法
doService(request, response);
}
catch (ServletException | IOException ex) {
failureCause = ex;
throw ex;
}
catch (Throwable ex) {
failureCause = ex;
throw new NestedServletException("Request processing failed", ex);
}
finally {
resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
logResult(request, response, failureCause, asyncManager);
publishRequestHandledEvent(request, response, startTime, failureCause);
}
processRequest()
方法中重点在doService(request, response);
,而其核心处理逻辑位于DispatchServletl类重写的方法,如下。
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
····
try {
//这里为实际分发控制器的逻辑,其内部是找到对应的handlerMapper
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);
}
}
if (requestPath != null) {
ServletRequestPathUtils.clearParsedRequestPath(request);
}
}
}
接下来看分发处理逻辑方法,其中重要的方法都使用了原生的注释。接下来分别分析核心源码。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
boolean multipartRequestParsed = false;
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);
}
}
}
}
首先是分析getHandler(),找到对应的处理器映射逻辑。
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;
}
我们将断点标记在getHandler
方法上时,可以清除看到handlerMappings
,如图。
这里,用户请求与处理器的映射关系都在RequestMapperHandlerMapping
中,而欢迎页处理请求则在WelcomePageHanderMapping
中进行映射。
以下为RequestMapperHandlerMapping中映射部分截图,可以看到用户的所有请求映射这里面都有:
getHandler()后的方法是通过比较request请求中method与HandlerMapper中相同url下的method,再进行唯一性校验,不通过异常,通过找到唯一的handler。
后续,通过handler找到处理的设配器,通过适配器得到一个ModelAndView对象,这个对象就是最后返回给前端页面的对象。
至此,一个请求完整映射到返回前端结束。
说明:这是实现了FramworkServlet的doService方法,FramworkServlet继承自HttpServlet,并且重写了父类中的doGet(),doPost(),doPut(),doDelete 等方法,在这些重写的方法里都调用了 processRquest() 方法做请求处理,进入processRquest()可以看到里面调用了FramworkServlet中定义的doService() 方法。
来源:https://www.cnblogs.com/fjrgg/p/14545387.html


猜你喜欢
- 本文实例为大家分享了Android实现支付宝记账饼图,点击旋转到最下面,供大家参考,具体内容如下代码:package com.example
- 查看和修改线程优先级1.题目JAVA中每个线程都有优化级属性,默认情况下,新建的线程和创建该线程的线程优先级是一样的。当线程调度器选择要运行
- 本文实例讲述了Android内容提供者ContentProvider用法。分享给大家供大家参考,具体如下:PersonContentProv
- 引言关于 Flutter 状态管理,公司项目使用的是Bloc方案。Bloc 其实本质上是 provider 的封装扩展库,整体通过 Inhe
- Java去掉指定字符串的开头的指定字符/** * 去掉指定字符串的开头的指定字符 *
- 1. 快速创建maven管理的SpringBoot项目1、访问 http://start.spring.io/2、 选择构建工具Maven
- 前言在C语言中,没有专门用来表示字符串的类型。C语言的字符串是一系列以’\0’为结尾的字符的集合。虽
- 本文实例为大家分享了UnityShader百叶窗展示的具体代码,供大家参考,具体内容如下shader实现以上百叶窗效果,主要通过shader
- 说到导出 Excel,我们首先会想到 poi、jsxl 等,使用这些工具会显得笨重,学习难度大。今天学习使用 JeecgBoot 中的 Au
- android给我们提供了一个spinner控件,这个控件主要就是一个列表,那么我们就来说说这个控件吧,这个控件在以前的也看见过,但今天还是
- 目录生成类注释生成类注解模板生成方法注释生成方法注解模板最近从eclipse转idea了,第一步当然是配置快捷键,模板等。但是!发生了一件贼
- Android ActionBarActivity设置全屏无标题实现方法总结前言:新建的Activity继承自ActionBar
- this.tclMain.Controls["tpgSize"].Parent = null; this.tclMain
- 一、文件上传的必要前提A form 表单的 enctype 取值必须是:multipart/form-data(默认值是:applicati
- Spring中有很多继承于aware中的接口,这些接口到底是做什么用到的。aware,翻译过来是知道的,已感知的,意识到的,所以这些接口从字
- 本文实例为大家分享了Android自定义圆环倒计时控件的具体代码,供大家参考,具体内容如下先来一张最终效果图:主要思路: 在画渐变
- 需求是在我按下按钮时,该变按钮颜色,使用户感觉到自己按了按钮,当松开的时候,变回原来的颜色。正常时:按下时:有人说,直接监听按钮的按下事件不
- Gituhb项目Volley源码中文注释项目我已经上传到github,欢迎大家fork和start.为什么写这篇博客本来文章是维护在gith
- eclipse导入Spring配置文件约束 Windows-Preference-XML-XMLCatalog点 Add 选Fil
- 零、关于HibernateHibernate是冬眠的意思,它是指动物的冬眠,但是本文讨论的Hibernate却与冬眠毫无关系,而是接下来要讨