SpringMVC中处理Http请求的原理详解
作者:nuomizhende45
SpingMVC处理Http请求原理
当一个http请求过来了首先经过的是DispatcherServlet这么一个前端控制器并调用了这个前端控制器的doService方法。
这个方法最终我们发现它调用了doDispatcher这么一个方法。这就是SpringMVC处理http请求的入口了。
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { if(this.logger.isDebugEnabled()) { String attributesSnapshot = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult()?" resumed":""; this.logger.debug("DispatcherServlet with name \'" + this.getServletName() + "\'" + attributesSnapshot + " processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]"); } HashMap attributesSnapshot1 = null; if(WebUtils.isIncludeRequest(request)) { attributesSnapshot1 = new HashMap(); Enumeration inputFlashMap = request.getAttributeNames(); label112: while(true) { String attrName; do { if(!inputFlashMap.hasMoreElements()) { break label112; } attrName = (String)inputFlashMap.nextElement(); } while(!this.cleanupAfterInclude && !attrName.startsWith("org.springframework.web.servlet")); attributesSnapshot1.put(attrName, request.getAttribute(attrName)); } } 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 inputFlashMap1 = this.flashMapManager.retrieveAndUpdate(request, response); if(inputFlashMap1 != null) { request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap1)); } request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap()); request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager); } try { this.doDispatch(request, response); } finally { if(!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted() && attributesSnapshot1 != null) { this.restoreAttributesAfterInclude(request, attributesSnapshot1); } } }
这个方法里面我们发现定义了一个ModelAndView将要返回的视图与数据,并且首先检测这个请求是不是一个上传的请求,然后根据这个请求获取对应的Handler,如果Handler不为空的话就根据这个handler获取对应的HandlerAdapter。接着调用拦截器链的所有前置拦截的这么一个方法,接着调用adapter的真正的处理方法处理请求,最后调用拦截器链中的所有后置拦截方法。
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { try { //定义一个空的ModelAndView ModelAndView err = null; Object dispatchException = null; try { //检查是否是上传请求 processedRequest = this.checkMultipart(request); multipartRequestParsed = processedRequest != request; //获取handler mappedHandler = this.getHandler(processedRequest); if(mappedHandler == null) { this.noHandlerFound(processedRequest, response); return; } //根据handler获取handlerAdapter HandlerAdapter err1 = this.getHandlerAdapter(mappedHandler.getHandler()); String method = request.getMethod(); boolean isGet = "GET".equals(method); if(isGet || "HEAD".equals(method)) { long lastModified = err1.getLastModified(request, mappedHandler.getHandler()); if(this.logger.isDebugEnabled()) { this.logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified); } if((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) { return; } } //前置拦截 if(!mappedHandler.applyPreHandle(processedRequest, response)) { return; } //真正处理 err = err1.handle(processedRequest, response, mappedHandler.getHandler()); if(asyncManager.isConcurrentHandlingStarted()) { return; } this.applyDefaultViewName(processedRequest, err); //后置拦截 mappedHandler.applyPostHandle(processedRequest, response, err); } //后面一些catch finally语句省略。。。。。
继续跟进这个getHandler方法看看具体是怎么实现的,发现就是循环遍历最开始初始化DispatcherServlet的时候初始化的那7个handlerMapping,去调用这些handlerMapping的getHandler方法;这里我们主要看这个RequestMappingHandlerMapping。
跟进发现是调用了RequestMappingHandlerMapping的父类AbstractHandlerMapping中的getHandler方法,并且这个方法又是去调用了getHandlerInternal来获取Handler的。
继续跟进这个getHandlerInternal方法,首先它根据这个request获取它的URI,接着通过uri获取对应的HandlerMethod对象最终返回了。
protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { String lookupPath = this.getUrlPathHelper().getLookupPathForRequest(request); if(this.logger.isDebugEnabled()) { this.logger.debug("Looking up handler method for path " + lookupPath); } this.mappingRegistry.acquireReadLock(); HandlerMethod var4; try { HandlerMethod handlerMethod = this.lookupHandlerMethod(lookupPath, request); if(this.logger.isDebugEnabled()) { if(handlerMethod != null) { this.logger.debug("Returning handler method [" + handlerMethod + "]"); } else { this.logger.debug("Did not find handler method for [" + lookupPath + "]"); } } var4 = handlerMethod != null?handlerMethod.createWithResolvedBean():null; } finally { this.mappingRegistry.releaseReadLock(); } return var4; }
跟进这个getLookupPathForRequest发现又调用了getPathWithinServletMapping方法。
这里我们就知道了这个lookupPath得到的就是这个请求的URI,拿到了这个URI接着就去调用lookupHandlerMethod方法了。
这里lookupHandlerMethod方法顾名思义就是通过这个URI根据请求的URI去寻找对应的HandlerMethod。
protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { ArrayList matches = new ArrayList(); //通过这个uri去Map中查询与那个HandlerMethod映射 List directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath); if(directPathMatches != null) { this.addMatchingMappings(directPathMatches, matches, request); } if(matches.isEmpty()) { this.addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request); } //若查询出这个uri有对应的映射关系 if(!matches.isEmpty()) { AbstractHandlerMethodMapping.MatchComparator comparator = new AbstractHandlerMethodMapping.MatchComparator(this.getMappingComparator(request)); //对映射关系排序 matches.sort(comparator); if(this.logger.isTraceEnabled()) { this.logger.trace("Found " + matches.size() + " matching mapping(s) for [" + lookupPath + "] : " + matches); } //获取排序后第一个HandlerMethod AbstractHandlerMethodMapping.Match bestMatch = (AbstractHandlerMethodMapping.Match)matches.get(0); if(matches.size() > 1) { if(CorsUtils.isPreFlightRequest(request)) { return PREFLIGHT_AMBIGUOUS_MATCH; } AbstractHandlerMethodMapping.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); } }
最终得到了这么一个包含了Handler与这个URI具体处理方法的一个HandlerMethod对象。
注意现在这个handler可能还没有被创建出来或者说没有得到,只是知道它的beanName。
最终还要调用这么一个createWithResolvedBean方法来得到。
获得了这个handler之后,又继续根据这个handler获得了HandlerExecutionChain。
public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { Object handler = this.getHandlerInternal(request); if(handler == null) { handler = this.getDefaultHandler(); } if(handler == null) { return null; } else { if(handler instanceof String) { String executionChain = (String)handler; handler = this.obtainApplicationContext().getBean(executionChain); } HandlerExecutionChain executionChain1 = this.getHandlerExecutionChain(handler, request); if(CorsUtils.isCorsRequest(request)) { CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request); CorsConfiguration handlerConfig = this.getCorsConfiguration(handler, request); CorsConfiguration config = globalConfig != null?globalConfig.combine(handlerConfig):handlerConfig; executionChain1 = this.getCorsHandlerExecutionChain(request, executionChain1, config); } return executionChain1; } }
所以得出最终结论getHandler这个方法最终所有通过这个URI返回了一个最开始注册的handler,然后通过 这个handler返回了一个包含这这个HandlerMethod以及一个拦截器链的这么一个对象。之后执行前置拦截器,handler方法,后置拦截,完成。
到此这篇关于SpingMVC中处理Http请求的原理详解的文章就介绍到这了,更多相关SpingMVC处理Http请求内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!