SpringMVC处理流程非常详细的讲解
环境:Spring5.3.241 请求入口 public class DispatcherServlet extends FrameworkServlet { protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HandlerExecutionChain mappedHandler = null; try { ModelAndView mv = null; Exception dispatchException = null; try { // 2.1.通过HandlerMapping获取请求处理链,该对象由处理程序(Controller,一般HandlerMethod对象)及拦截器(Interceptor)组成 mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 2.2.根据2.1获取的处理程序(HandlerMethod)对象确定能够处理该处理程序的HandlerAdapter对象 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // ... // 2.3.执行处理程序之前,执行拦截器preHandle方法,如果返回了false,本次请求将被终止 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 2.4.真正的执行处理程序 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // ... // 2.5.执行处理程序之后,执行拦截器postHandle方法 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { dispatchException = new NestedServletException("Handler dispatch failed", err); } // 2.6.处理结果,根据处理程序是否发生异常,是否返回有ModelAndView对象进行结果的处理 processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } // ... } }2 处理请求2.1 获取请求处理链
该步骤通过 HandlerMapping 获取 HandlerExecutionChain 处理器执行链。 public class DispatcherServlet { protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { if (this.handlerMappings != null) { // 遍历当前容器中注册的所有HandlerMapping对象 for (HandlerMapping mapping : this.handlerMappings) { // 针对Controller接口,使用的是RequestMappingHandlerMapping对象 HandlerExecutionChain handler = mapping.getHandler(request); if (handler != null) { return handler; } } } return null; } }
这里以 RequestMappingHandlerMapping 为例
mapping.getHandler(request)方法调用流程如下: public abstract class AbstractHandlerMapping { public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception { // 调用子类实现的getHandlerInternal方法 Object handler = getHandlerInternal(request); // ... // 根据查找到的处理程序封装到处理程序执行链 // 这里会将拦截器也添加其中 HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request); // ...这里是跨域相关的配置 return executionChain; } protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) { HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ? (HandlerExecutionChain) handler : new HandlerExecutionChain(handler)); for (HandlerInterceptor interceptor : this.adaptedInterceptors) { if (interceptor instanceof MappedInterceptor) { MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor; if (mappedInterceptor.matches(request)) { chain.addInterceptor(mappedInterceptor.getInterceptor()); } } else { chain.addInterceptor(interceptor); } } return chain; } }
调用子类 RequestMappingInfoHandlerMapping#getHandlerInternal 实现。 public abstract class RequestMappingInfoHandlerMapping extends AbstractHandlerMethodMapping { protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { request.removeAttribute(PRODUCIBLE_MEDIA_TYPES_ATTRIBUTE); try { // 又调父类的实现 (⊙o⊙)… return super.getHandlerInternal(request); } } }
调用父类 AbstractHandlerMethodMapping#getHandlerInternal 方法 public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMapping implements InitializingBean { private final MappingRegistry mappingRegistry = new MappingRegistry(); protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception { // 根据当前的请求获取请求的uri String lookupPath = initLookupPath(request); this.mappingRegistry.acquireReadLock(); try { HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request); return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null); } } protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception { List matches = new ArrayList<>(); // 系统启动时初始化RequestMappingHandlerMapping解析了整个系统中所有的Controller然后注册到MappingRegistry中 // 根据当前的请求uri,对应List对象,相同的uri可能对应不同的request method,所以这里返回的是List集合 List directPathMatches = this.mappingRegistry.getMappingsByDirectPath(lookupPath); if (directPathMatches != null) { // 该方法内部会根据找到的RequestMappingInfo进行遍历,根据请求信息逐个的判断对应@RequestMapping配置的属性是否匹配 addMatchingMappings(directPathMatches, matches, request); } if (matches.isEmpty()) { addMatchingMappings(this.mappingRegistry.getRegistrations().keySet(), matches, request); } // 下面if的逻辑就是判断如果找到了匹配并且存在多个会找出最合适的 if (!matches.isEmpty()) { Match bestMatch = matches.get(0); if (matches.size() > 1) { Comparator comparator = new MatchComparator(getMappingComparator(request)); matches.sort(comparator); bestMatch = matches.get(0); if (CorsUtils.isPreFlightRequest(request)) { for (Match match : matches) { if (match.hasCorsConfig()) { return PREFLIGHT_AMBIGUOUS_MATCH; } } } else { Match secondBestMatch = 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()); // 将当前请求uri保存到request对象中setAttribute handleMatch(bestMatch.mapping, lookupPath, request); // 返回当前uri对应的HandlerMethod对象 return bestMatch.getHandlerMethod(); } } protected void handleMatch(T mapping, String lookupPath, HttpServletRequest request) { request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath); } }2.2 获取HandlerAdapter
在上一步中通过 HandlerMapping 找到了相应的 HandlerMethod 对象,最后封装到了 HandlerExecutionChain 中,接下来就是根据 HandlerMethod 查找合适的 HandlerAdapter 处理程序。 public class DispatcherServlet { protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { // 这里的参数handler一般都是HandlerMethod对象 for (HandlerAdapter adapter : this.handlerAdapters) { // 这个根据handler判断哪个HandlerAdapter支持,一般都是RequestMappingHandlerAdapter if (adapter.supports(handler)) { return adapter; } } } throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler"); } }
RequestMappingHandlerAdapter 这调用的是父类方法 public abstract class AbstractHandlerMethodAdapter { public final boolean supports(Object handler) { return (handler instanceof HandlerMethod && supportsInternal((HandlerMethod) handler)); } } public class RequestMappingHandlerAdapter { protected boolean supportsInternal(HandlerMethod handlerMethod) { return true; } }2.3 执行拦截器preHandle方法
在真正调用处理程序前,执行拦截器preHandle方法 public class HandlerExecutionChain { boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception { for (int i = 0; i < this.interceptorList.size(); i++) { HandlerInterceptor interceptor = this.interceptorList.get(i); // 如果任何一个拦截器返回了false,本次请求都会被终止 if (!interceptor.preHandle(request, response, this.handler)) { // 该拦截器的完成回调会被执行 triggerAfterCompletion(request, response, null); return false; } this.interceptorIndex = i; } return true; } }2.4 实际请求处理 public class DispatcherServlet { protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); } }
AbstractHandlerMethodAdapter public abstract class AbstractHandlerMethodAdapter { public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 子类重写了该方法 return handleInternal(request, response, (HandlerMethod) handler); } }
RequestMappingHandlerAdapter public class RequestMappingHandlerAdapter { protected ModelAndView handleInternal(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ModelAndView mav; if (this.synchronizeOnSession) { // ... } else { // No synchronization on session demanded at all... // 执行HandlerMethod调用 mav = invokeHandlerMethod(request, response, handlerMethod); } // ... return mav; } protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { ServletWebRequest webRequest = new ServletWebRequest(request, response); try { // 创建数据绑定工厂,主要作用就是将请求的参数信息与Controller方法的参数进行绑定(数据类型的转换)及参数校验 WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod); // 处理@ModelAttribute和@SessionAttribute注解,它将做两件事: // 1.将@SessionAttribute注解的方法的相关数据合并到下面的ModelAndViewContainer中 // 2.将@ModelAttribute注解的方法返回值添加到ModelAndViewContainer中 ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory); // 实际HandlerMethod调用对象 ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod); if (this.argumentResolvers != null) { // 设置参数解析器 invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers); } if (this.returnValueHandlers != null) { // 设置Controller方法返回值的处理器 invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers); } invocableMethod.setDataBinderFactory(binderFactory); invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer); ModelAndViewContainer mavContainer = new ModelAndViewContainer(); mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request)); // 执行上面说的两个步骤 modelFactory.initModel(webRequest, mavContainer, invocableMethod); mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect); // ... // 执行调用HandlerMethod // 在这个过程中会应用到参数解析器和返回值处理器,这里就不展开说了 invocableMethod.invokeAndHandle(webRequest, mavContainer); if (asyncManager.isConcurrentHandlingStarted()) { return null; } // 这里会返回ModelAndView对象,这个根据情况,如果你是RestController,那么在通过返回值处理器就已经将结果进行了输出如使用@ResponseBody注解的方法 // 如果是RestController,请求结果就提前输出了,同时会将ModelAndViewContainer的requestHandled属性设置为true。 return getModelAndView(mavContainer, modelFactory, webRequest); } finally { webRequest.requestCompleted(); } } private ModelAndView getModelAndView(ModelAndViewContainer mavContainer, ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception { modelFactory.updateModel(webRequest, mavContainer); // 如果是@ResponseBody注解的方法,那么直接返回null if (mavContainer.isRequestHandled()) { return null; } ModelMap model = mavContainer.getModel(); ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus()); if (!mavContainer.isViewReference()) { mav.setView((View) mavContainer.getView()); } // ... return mav; } }2.5 执行拦截器postHandle方法 public class HandlerExecutionChain { void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception { for (int i = this.interceptorList.size() - 1; i >= 0; i--) { HandlerInterceptor interceptor = this.interceptorList.get(i); interceptor.postHandle(request, response, this.handler, mv); } } }2.6 处理结果 public class DispatcherServlet { protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception { boolean errorView = false; // 在处理过程中如果出现了异常会进入这里进行异常处理 if (exception != null) { if (exception instanceof ModelAndViewDefiningException) { logger.debug("ModelAndViewDefiningException encountered", exception); mv = ((ModelAndViewDefiningException) exception).getModelAndView(); } else { Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null); mv = processHandlerException(request, response, handler, exception); errorView = (mv != null); } } // 如果Controller方法返回有ModelAndView if (mv != null && !mv.wasCleared()) { // 进行视图的渲染输出到客户端 render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } // 如果是RestController接口,那么上面的代码都不会执行 if (mappedHandler != null) { // 执行拦截器的afterCompletion回调方法 mappedHandler.triggerAfterCompletion(request, response, null); } } }
完毕!!!
求关注
SpringMVC非常实用的过滤器
SpringMVC参数统一验证方法
SpringMVC跨域CORS的各种解决方式
SpringMVC内嵌Tomcat零配置
完全自定义实现SpringMVC核心组件
完全自定义实现SpringMVC核心组件
动态清零是制胜法宝来源经济日报今年3月份以来,面对隐匿性传播性都明显增强的奥密克戎变异株,我国坚持动态清零总方针,最大限度遏制了病毒蔓延,全国疫情整体呈现下降态势。从武汉保卫战,到疫情常态化防控,再
刻瓷艺术简介刻瓷艺术简介晚清刻瓷人物提梁壶欣赏提起刻瓷画,许多人都会感到陌生。刻瓷作为中国传统陶瓷装饰技法之一,采用钻石等硬质工具在瓷器上镌刻出山水花鸟动物人物书法等纹饰,根据画面需要再填以墨
保时捷惹怒各路大V,人民网发话了如果你买了辆豪车,却被告知少了个配件,你会怎么做?这个瓜可谓是吃得一波三折,且听狐妹细细说来。代金券是几个意思老规矩,先上时间线。从三月份开始,有不少保时捷车主到各大平台上投诉,称
市面上逐渐消失的童年零食,全吃过的结婚了吧!真的老了今天来一波90年代的回忆杀,对于那个时代,别的记不清了,只能记得当时的零食到底有多好吃,满满的回忆,下面我们一起来看,看你们吃过了多少种,这里要是都吃过的应该已经结婚了!夏威夷冰棍
推迟婚约放弃陪考他们在方舱里用真情守护病患我手下的这批护士,个个都是能打硬仗的。电话那头,驻守船舶馆方舱的上海第九人民医院黄浦分院护士长陈婕坚定地说,这里最高峰时有近700位病人,而我们总共只有36名护士,面临着前所未有的
血型能决定性格和寿命?A型AB型B型O型,哪种更容易患癌?我是O型血,我是长寿命,你们羡慕不来。少得瑟了,我听说,这O型血更容易患癌,劝你小心点。公园里,下着棋的老王和老刘因为血型吵了起来。老王自从上次看了一篇文章里说O型血的人更长寿之后
从肺癌晚期到肿瘤消失,人民日报记者凌志军曾抗癌成功在普通人的观念里,癌症基本上已经和不治之症划上了等号,不过随着医疗越来越发达,许多早期癌症大部分都有治愈的机会。人民日报有位记者,他却实现了从肺癌晚期到肿瘤消失,从死神手里夺回了自
首次表彰!柳北区这些集体和个人上榜!看看有你认识的吗?5月13日,20182021年全区人大代表工作先进集体和先进个人表彰大会在南宁举行。这是自治区人大常委会首次开展全区人大代表工作先进集体和先进个人评选表彰工作。其中,柳北区人大常委
民间故事男子错杀家中黄牛,夜里黄牛托梦多谢主人救命之恩明朝万历年间,南沟村位于太行山脚下,在这个村子里有一个庄稼汉叫刘老根,他长得大高个,相貌粗犷,性格却是憨厚老实。刘老根四岁时父亲便去世了,他是瞎子老娘孙氏一把屎一把尿给拉扯大的,从
当代年轻人性爱实录爱还在,性没了上个月,十点人物志发布了一篇老年人去看男科的文章,后台反响热烈,很多读者在围观一群老年人晚年生活的荒诞与困境之余,也顺道吐槽了自己性生活的不如意。我们惊讶地发现,相比老年人对性生活
昔日何榜成笑话,八面玲珑也抵不住人走茶凉,何炅衰落太现实人走茶凉是一种什么感觉?这不免让人想起了何炅之前与现在的处境。曾有近乎半个娱乐圈人士,贡献了两组堪称盛世的生日祝福排行榜。他们凌晨时分,通过社交平台准时送上生日祝福。其中包含一线明
吃饱喝足不知道去哪里玩?这份新出炉的名单一定要收藏好了近日,山东省文化和旅游厅公布第二批山东省级夜间文化和旅游消费集聚区名单。第二批山东省级夜间文化和旅游消费集聚区名单(共31个)济南华谊兄弟(济南)电影小镇融汇济南老商埠文化旅游休闲
今日重阳!赶紧收藏长沙县这些登高好去处今天是农历九月初九重阳节,二九相重,亦称重九。九九谐音久久,重阳因此有了长长久久之意。自古以来,登高就是重阳的传统习俗。唐代诗人王维曾写下遥知兄弟登高处,遍插茱萸少一人,成为流传千
印度继续冻结216亿资产小米回应感到失望仍会保护商业利益小米集团今年4月底遭到印度执法单位扣押了555。1亿卢比(约合48亿元人民币)资产。印度上诉机构日前确认印度执法单位有权冻结小米该笔资产。对于印度上诉机构裁决,小米表示感到失望,称
新能源配储能经济账怎么算?当前我国储能正呈快速多元化发展趋势。与此同时,成本与商业模式问题依然困扰行业。新能源配储能经济账应该怎么算?记者近期对此展开调查。新能源的快速发展以及电网安全稳定运行的需求使得储能
javaer学习GO第一天(hello)十年java,感觉瓶颈严重。记录学习go的经历。喜欢就一起来学习下不同的语言。目前大厂都喜欢用go来中间价,go天然的并发优势(在设计语言阶段就开始考虑并发)。go的协程(goro
三星电子宣布2027年量产1。4纳米芯片三星电子宣布2027年量产1。4纳米芯片财联社10月4日电,据韩联社报道,三星电子3日宣布于2027年量产1。4纳米工艺的芯片。三星电子当天在美国加州硅谷举办三星晶圆代工论坛SAF
关于化学品与全球气候变暖问题李政禹摘要欧盟化学品管理局官网上的该文稿简要介绍了什么是温室效应温室气体及其来源以及欧盟正在采取的缓解全球气候变暖措施等科学知识。为了宣传普及化学品健全管理知识,现将原文的中文翻译
RabbitMQ发布订阅模式将向多个消费者传递一条消息。这种模式被称为发布订阅。使用fanout的exchanger,默认会忽略routingkey的值。fanout类型的exchanger,会将所有接收到的
事关首套房贷款利率,央行银保监会发布通知中国人民银行中国银行保险监督管理委员会关于阶段性调整差别化住房信贷政策的通知中国人民银行上海总部,各分行营业管理部,各省会(首府)城市中心支行副省级城市中心支行各银保监局为坚持房子
推进双碳,新五大发电有诗与远方,也有眼下的苟且推进双碳,构建新能源为主体新型电力系统下,两网新五大发电将会迎来前所未有的机遇,同样也面临的一定的挑战,有诗与远方,也有着眼下的苟且。新五大发电高光时刻2020年9月22日,我国首
重磅!A股关键时刻,多位私募大佬发声!王庆刘晓龙张智威陆航国庆长假期间,中国基金报邀请多家私募公司董事长总经理或投资总监,对前三季度股市进行分析总结,展望四季度A股投资机会,仅供投资者参考。重阳投资王庆市场正在孕育新一轮结构性行情重阳投资