Java源码分析SpringMVC执行流程 | 您所在的位置:网站首页 › javaspringmvc流程 › Java源码分析SpringMVC执行流程 |
Java源码分析SpringMVC执行流程
发布时间:2023-04-20 16:13:04
来源:亿速云
阅读:58
作者:iii
栏目:开发技术
本篇内容介绍了“Java源码分析SpringMVC执行流程”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! 先看流程先看一下SpringMVC执行流程再看源码,有助理解: ⽤户发送请求⾄前端控制器DispatcherServlet。 DispatcherServlet 收到请求调⽤ HandlerMapping 处理器映射器。 处理器映射器找到具体的处理器(可以根据xml配置、注解进⾏查找),⽣成处理器及处理器拦截器(如果有则⽣成)⼀并返回给DispatcherServlet。 DispatcherServlet调⽤HandlerAdapter处理器适配器。 HandlerAdapter经过适配调⽤具体的处理器(Controller,也叫后端控制器) Controller执⾏完成返回ModelAndView。 HandlerAdapter 将 Controller 执⾏结果 ModelAndView 返回给DispatcherServlet。 DispatcherServlet将ModelAndView传给ViewReslover视图解析器。 ViewReslover解析后返回具体View。 DispatcherServlet根据View进⾏渲染视图(即将模型数据填充⾄视图中)。 DispatcherServlet 响应⽤户。 我们都知道当从用户发起请求到后端是,首先走的就是DispatcherServlet,接着就会调用doService()方法执行业务逻辑,doService()方法也只是一个中转站,实际执行逻辑的是doDispatch()方法,且看源码: @Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { logRequest(request); // 省略部分源码 try { // 执行实际逻辑 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); } } ServletRequestPathUtils.setParsedRequestPath(previousRequestPath, request); } }doDispatch 方法: 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); // 为当前请求获取映射处理器 mappedHandler = getHandler(processedRequest); if (mappedHandler == null) { noHandlerFound(processedRequest, response); return; } // 获取映射处理器适配器 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; } // 实际调用的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); } } } }下面来看一下其中几个重要的方法: 1.getHandler(HttpServletRequest request)方法:该方法是处理当前请求找到合适的HandlerMapping,并返回一个HandlerExecutionChain,HandlerExecutionChain,HandlerExecutionChain包含了具体的处理器(handler)和拦截器列表。 HandlerMapping 默认的实现有org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping 和 org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping。 @Nullable 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; }2.getHandlerAdapter(Object handler) 根据HandlerExecutionChain中的handler来获取处理器适配器(HandlerAdapter), protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException { if (this.handlerAdapters != null) { for (HandlerAdapter adapter : this.handlerAdapters) { 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"); }HandlerAdapter有两个默认实现类,分别是 org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter和 org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,前者用于没有使用模板引擎的请求,后者用于使用了模板引擎的接口。 实际处理请求的是HandlerAdapter的handle方法,如果是没有使用例如JSP等的模板引擎,handle方法就会返回null,如果使用了模板引擎就会返回一个ModelAndView对象。 ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());handle方法最终调用的是Controller接口的 handleRequest(HttpServletRequest request, HttpServletResponse response) 方法来处理请求。 以SimpleControllerHandlerAdapter#handle方法源码为例: @Override @Nullable public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return ((Controller) handler).handleRequest(request, response); }3.processDispatchResult方法用于处理转发结果,该结果要么是一个ModelAndView,要么抛异常。 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); } } // Did the handler return a view to render? if (mv != null && !mv.wasCleared()) { //加载视图 render(mv, request, response); if (errorView) { WebUtils.clearErrorRequestAttributes(request); } } else { if (logger.isTraceEnabled()) { logger.trace("No view rendering, null ModelAndView returned."); } } if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) { // Concurrent handling started during a forward return; } if (mappedHandler != null) { // Exception (if any) is already handled.. mappedHandler.triggerAfterCompletion(request, response, null); } }processDispatchResult方法中在正常情况下会调用render方法。 4.render方法用来通过名称呈现视图,它也是请求处理的最后一步。 protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception { // Determine locale for request and apply it to the response. Locale locale = (this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale()); response.setLocale(locale); View view; String viewName = mv.getViewName(); if (viewName != null) { // 通过视图名称获取视图 view = resolveViewName(viewName, mv.getModelInternal(), locale, request); if (view == null) { throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + getServletName() + "'"); } } else { // No need to lookup: the ModelAndView object contains the actual View object. view = mv.getView(); if (view == null) { throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " + "View object in servlet with name '" + getServletName() + "'"); } } // Delegate to the View object for rendering. if (logger.isTraceEnabled()) { logger.trace("Rendering view [" + view + "] "); } try { if (mv.getStatus() != null) { response.setStatus(mv.getStatus().value()); } //渲染视图 view.render(mv.getModelInternal(), request, response); } catch (Exception ex) { if (logger.isDebugEnabled()) { logger.debug("Error rendering view [" + view + "]", ex); } throw ex; } }DispatcherServlet的render方法是对视图View的封装,最后调用的还是View的render方法。 resolveViewName方法用于解析视图名称,它会通过视图解析器ViewResolver的resolveViewName方法解析视图并返回一个视图View,然后再通过View的render方法渲染视图,至于是怎么渲染视图的这里就不介绍了,感兴趣的可以自行查看源码。 protected View resolveViewName(String viewName, @Nullable Map model, Locale locale, HttpServletRequest request) throws Exception { if (this.viewResolvers != null) { for (ViewResolver viewResolver : this.viewResolvers) { View view = viewResolver.resolveViewName(viewName, locale); if (view != null) { return view; } } } return null; }“Java源码分析SpringMVC执行流程”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章! 推荐阅读: java中如何实现生成器和迭代器 从零开始,搭建网络管理系统-前期准备免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:[email protected]进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。 java springmvc 上一篇新闻:Vue怎么实现轮播图组件封装 下一篇新闻:Vue表格首列相同数据合并怎么实现 猜你喜欢 springBoot启动时让方法自动执行的方法 python 如何提取PPT中所有文字的方法 JavaWeb中怎么使用Filter和Listener python 如何自动监控新邮件并读取 MySQL和Python怎么交互 spring-boot-maven-plugin引入出现爆红问题怎么回事 Mybatis-Plus select如何不显示全部字段 mysql字符集相关知识大全 Python中删除文件的几种方法介绍 如何解决mybatis-plus实体类中出现非数据库映射字段的问题 |
CopyRight 2018-2019 实验室设备网 版权所有 |