本篇内容介绍了“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<String, Object> 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执行流程”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。