springBoot2.6.2映射请求原理(源码分析)
2022/1/13 22:34:05
本文主要是介绍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.2映射请求原理(源码分析)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-23Springboot应用的多环境打包入门
- 2024-11-23Springboot应用的生产发布入门教程
- 2024-11-23Python编程入门指南
- 2024-11-23Java创业入门:从零开始的编程之旅
- 2024-11-23Java创业入门:新手必读的Java编程与创业指南
- 2024-11-23Java对接阿里云智能语音服务入门详解
- 2024-11-23Java对接阿里云智能语音服务入门教程
- 2024-11-23JAVA对接阿里云智能语音服务入门教程
- 2024-11-23Java副业入门:初学者的简单教程
- 2024-11-23JAVA副业入门:初学者的实战指南