springBoot2.6.2映射请求原理(源码分析)
作者:互联网
文章目录
- 前言
- 1.`分析doGet,doPost请求`
- 二. `查看processRequest方法`
- 三. `查看doServlet方法`
- 四.`回过头看看DipatcherServlet类`
- 五.`分析doDispatch`
- 六 `查验映射匹配原理`
你来看我啦啊
前言
由于springBoot底层还是使用的springMVC,因此前端的所有请求都会通过DispatcherServlet前端控制器.
因此我们从DispatcherServlet开始分析
1.分析doGet,doPost请求
在FrameworkServlet中发现,其重写了HttpServlet的doGet,doPost等请求
我们可以发现重写的方法均调用了processRequest方法,即将请求处理全部交给processRequest()方法
protected final void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processRequest(request, response);
}
protected final void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processRequest(request, response);
}
protected final void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processRequest(request, response);
}
protected final void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
this.processRequest(request, response);
}
二. 查看processRequest方法
protected final void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// 获取系统当前时间戳
long startTime = System.currentTimeMillis();
//初始化异常类
Throwable failureCause = null;
//获取LocaleContextHolder方法中ThreadLocal保存的上一个线程的request到previousLocaleContext
LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
// 初始化构建新的上下文 buildLocaleContext中return new SimpleLocaleContext(request.getLocale());
LocaleContext localeContext = this.buildLocaleContext(request);
//获取上一个请求保存的RequestAttributes
RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
// 初始化构建新的ServletRequestAttributes
ServletRequestAttributes requestAttributes = this.buildRequestAttributes(request, response, previousAttributes);
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new FrameworkServlet.RequestBindingInterceptor());
// 初始化配置当前线程
this.initContextHolders(request, localeContext, requestAttributes);
try {
//调用doService处理请求 .上面都是初始化配置一些东西,为此做准备
this.doService(request, response);
} catch (IOException | ServletException var16) {
failureCause = var16;
throw var16;
} catch (Throwable var17) {
failureCause = var17;
throw new NestedServletException("Request processing failed", var17);
} finally {
this.resetContextHolders(request, previousLocaleContext, previousAttributes);
if (requestAttributes != null) {
requestAttributes.requestCompleted();
}
this.logResult(request, response, (Throwable)failureCause, asyncManager);
this.publishRequestHandledEvent(request, response, startTime, (Throwable)failureCause);
}
}
三. 查看doServlet方法
FreameworkServlet没有实现....
protected abstract void doService(HttpServletRequest request, HttpServletResponse response) throws Exception;
而他的子类DipatcherServlet对其进行了实现,我们再回过头看看DipatcherServlet类
四.回过头看看DipatcherServlet类
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
this.logRequest(request);
Map<String, Object> attributesSnapshot = null;
if (WebUtils.isIncludeRequest(request)) {
attributesSnapshot = new HashMap();
Enumeration attrNames = request.getAttributeNames();
label116:
while(true) {
String attrName;
do {
if (!attrNames.hasMoreElements()) {
break label116;
}
attrName = (String)attrNames.nextElement();
} while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet"));
attributesSnapshot.put(attrName, request.getAttribute(attrName));
}
}
// web应用上下文对象放置在Application域中,初始化设置视图
request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.getWebApplicationContext());
request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
request.setAttribute(THEME_SOURCE_ATTRIBUTE, this.getThemeSource());
if (this.flashMapManager != null) {
FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
if (inputFlashMap != null) {
request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
}
request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
}
RequestPath previousRequestPath = null;
if (this.parseRequestPath) {
previousRequestPath = (RequestPath)request.getAttribute(ServletRequestPathUtils.PATH_ATTRIBUTE);
ServletRequestPathUtils.parseAndCache(request);
}
try {
this.doDispatch(request, response);
} finally {
if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot != null) {
this.restoreAttributesAfterInclude(request, attributesSnapshot);
}
if (this.parseRequestPath) {
ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request);
}
}
}
源码分析所有的请求不管POST还是GET都先经过doService 方法,其中都会调用 org.springframework.web.servlet.DispatcherServlet 实现doService()的doDispatch()方法
五.分析doDispatch
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
//获得请求的详细信息
HttpServletRequest processedRequest = request;
HandlerExecutionChain mappedHandler = null;
//文件上传请求默认false
boolean multipartRequestParsed = false;
//请求期间是否异步
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
try {
try {
//视图模型初始化
ModelAndView mv = null;
//异常初始化
Object dispatchException = null;
try {
//检查请求是否为文件上传的请求的
processedRequest = this.checkMultipart(request);
//不是文件上传的请求的赋值给multipartRequestParsed
multipartRequestParsed = processedRequest != request;
// 找到当前请求使用哪个Handler(Controller的方法)处理
mappedHandler = this.getHandler(processedRequest);
if (mappedHandler == null) {
this.noHandlerFound(processedRequest, response);
return;
}
//寻找适配Handler的请求
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
String method = request.getMethod();
boolean isGet = HttpMethod.GET.matches(method);
if (isGet || HttpMethod.HEAD.matches(method)) {
long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
return;
}
}
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
if (asyncManager.isConcurrentHandlingStarted()) {
return;
}
this.applyDefaultViewName(processedRequest, mv);
mappedHandler.applyPostHandle(processedRequest, response, mv);
} catch (Exception var20) {
dispatchException = var20;
} catch (Throwable var21) {
dispatchException = new NestedServletException("Handler dispatch failed", var21);
}
this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
} catch (Exception var22) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
} catch (Throwable var23) {
this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
}
} finally {
if (asyncManager.isConcurrentHandlingStarted()) {
if (mappedHandler != null) {
mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
}
} else if (multipartRequestParsed) {
this.cleanupMultipart(processedRequest);
}
}
}
其中debug step into
断点
//寻找适配Handler的请求
HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
handlerMappings映射处理器.
RequestMappingHandlerMapping:保存了所有@RequestMapping 和handler的映射规则.
六 查验映射匹配原理
在AbstractHandlerMethodMapping类中有
@Nullable
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
List<AbstractHandlerMethodMapping<T>.Match> matches = new ArrayList();
List<T> directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath);
if (directPathMatches != null) {
this.addMatchingMappings(directPathMatches, matches, request);
}
if (matches.isEmpty()) {
this.addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request);
}
if (matches.isEmpty()) {
return this.handleNoMatch(this.mappingRegistry.getRegistrations().keySet(), lookupPath, request);
} else {
AbstractHandlerMethodMapping<T>.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (matches.size() > 1) {
Comparator<AbstractHandlerMethodMapping<T>.Match> comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request));
matches.sort(comparator);
bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0);
if (this.logger.isTraceEnabled()) {
this.logger.trace(matches.size() + " matching mappings: " + matches);
}
if (CorsUtils.isPreFlightRequest(request)) {
Iterator var7 = matches.iterator();
while(var7.hasNext()) {
AbstractHandlerMethodMapping<T>.Match match = (AbstractHandlerMethodMapping.Match)var7.next();
if (match.hasCorsConfig()) {
return PREFLIGHT_AMBIGUOUS_MATCH;
}
}
} else {
AbstractHandlerMethodMapping<T>.Match secondBestMatch = (AbstractHandlerMethodMapping.Match)matches.get(1);
if (comparator.compare(bestMatch, secondBestMatch) == 0) {
Method m1 = bestMatch.getHandlerMethod().getMethod();
Method m2 = secondBestMatch.getHandlerMethod().getMethod();
String uri = request.getRequestURI();
throw new IllegalStateException("Ambiguous handler methods mapped for '" + uri + "': {" + m1 + ", " + m2 + "}");
}
}
}
request.setAttribute(BEST_MATCHING_HANDLER_ATTRIBUTE, bestMatch.getHandlerMethod());
this.handleMatch(bestMatch.mapping, lookupPath, request);
return bestMatch.getHandlerMethod();
}
}
由上述源码可以看出当匹配值>1时他会经过一系列排序比较测试.之后报错该映射有两个处理器可以处理.
至此就可以理解映射路径和处理类型条件必须唯一!
标签:springBoot2.6,映射,matches,mappedHandler,request,源码,null,response,processedRequest 来源: https://blog.csdn.net/m0_50913327/article/details/122474339