1.在springMvc中负责处理请求的类为DispatcherServlet,这个类与我们传统的Servlet是一样的。我们来看看它的继承图

2. 我们发现DispatcherServlet也继承了HttpServlet,所以DispatcherServlet在处理请求时也会从service()方法开始。知道这一点后我们开始分析它的处理过程。

(1).我们在ApplicationFilterChain中的internalDoFilter()方法中打断点(至于为什么从这儿开始,需要去看Tomcat)

private void internalDoFilter(ServletRequest request,ServletResponse response)throws IOException, ServletException {// Call the next filter if there is oneif (pos < n) {ApplicationFilterConfig filterConfig = filters[pos++];try {Filter filter = filterConfig.getFilter();if (request.isAsyncSupported() && "false".equalsIgnoreCase(filterConfig.getFilterDef().getAsyncSupported())) {request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);}if( Globals.IS_SECURITY_ENABLED ) {final ServletRequest req = request;final ServletResponse res = response;Principal principal =((HttpServletRequest) req).getUserPrincipal();Object[] args = new Object[]{req, res, this};SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);} else {filter.doFilter(request, response, this);}} catch (IOException | ServletException | RuntimeException e) {throw e;} catch (Throwable e) {e = ExceptionUtils.unwrapInvocationTargetException(e);ExceptionUtils.handleThrowable(e);throw new ServletException(sm.getString("filterChain.filter"), e);}return;}// We fell off the end of the chain -- call the servlet instancetry {if (ApplicationDispatcher.WRAP_SAME_OBJECT) {lastServicedRequest.set(request);lastServicedResponse.set(response);}if (request.isAsyncSupported() && !servletSupportsAsync) {request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR,Boolean.FALSE);}// Use potentially wrapped request from this pointif ((request instanceof HttpServletRequest) &&(response instanceof HttpServletResponse) &&Globals.IS_SECURITY_ENABLED ) {final ServletRequest req = request;final ServletResponse res = response;Principal principal =((HttpServletRequest) req).getUserPrincipal();Object[] args = new Object[]{req, res};SecurityUtil.doAsPrivilege("service",servlet,classTypeUsedInService,args,principal);} else {servlet.service(request, response);                    //在这里打断点,进入到我们的service方法}} catch (IOException | ServletException | RuntimeException e) {throw e;} catch (Throwable e) {e = ExceptionUtils.unwrapInvocationTargetException(e);ExceptionUtils.handleThrowable(e);throw new ServletException(sm.getString("filterChain.servlet"), e);} finally {if (ApplicationDispatcher.WRAP_SAME_OBJECT) {lastServicedRequest.set(null);lastServicedResponse.set(null);}}}

(2)进入到FrameworkServlet中的service方法(注意在FrameworkServlet中重写了HttpServlet中的service方法)

   @Overrideprotected void service(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());            //HttpMethod为枚举类型,成员为GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;if (HttpMethod.PATCH == httpMethod || httpMethod == null) {           //如果请求方法为空,或者是PATCHprocessRequest(request, response);                                       //处理请求}else {super.service(request, response);                                    //交给父类进行处理,本例中我们是get请求,所以转到这里}}

(3)进入到父类HttpServlet中的service方法

 protected void service(HttpServletRequest req, HttpServletResponse resp)throws ServletException, IOException {String method = req.getMethod();                                  //获取请求的方法if (method.equals(METHOD_GET)) {long lastModified = getLastModified(req);if (lastModified == -1) {// servlet doesn't support if-modified-since, no reason// to go through further expensive logic
                doGet(req, resp);                                         //执行get请求} else {long ifModifiedSince;try {ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);} catch (IllegalArgumentException iae) {// Invalid date header - proceed as if none was setifModifiedSince = -1;}if (ifModifiedSince < (lastModified / 1000 * 1000)) {// If the servlet mod time is later, call doGet()// Round down to the nearest second for a proper compare// A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);doGet(req, resp);} else {resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);}}} else if (method.equals(METHOD_HEAD)) {long lastModified = getLastModified(req);maybeSetLastModified(resp, lastModified);doHead(req, resp);} else if (method.equals(METHOD_POST)) {doPost(req, resp);} else if (method.equals(METHOD_PUT)) {doPut(req, resp);} else if (method.equals(METHOD_DELETE)) {doDelete(req, resp);} else if (method.equals(METHOD_OPTIONS)) {doOptions(req,resp);} else if (method.equals(METHOD_TRACE)) {doTrace(req,resp);} else {//// Note that this means NO servlet supports whatever// method was requested, anywhere on this server.//
String errMsg = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[1];errArgs[0] = method;errMsg = MessageFormat.format(errMsg, errArgs);resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);}}

(4)由于doGet方法也被我们的FrameworkServlet重写,所以这里转向FrameworkServlet类

@Overrideprotected final void doGet(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {processRequest(request, response);   //我们在这里发现最终还是会到达processRequest方法}

(4)我们来看看FrameworkServlet中的processRequest方法

protected final void processRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {long startTime = System.currentTimeMillis();                   //在本篇中只介绍大致的执行过程,这里不详细介绍。。。。Throwable failureCause = null;LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();LocaleContext localeContext = buildLocaleContext(request);RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());initContextHolders(request, localeContext, requestAttributes);try {doService(request, response);                         //我们关心这个方法,发现它会转向doService方法                  }catch (ServletException ex) {failureCause = ex;throw ex;}catch (IOException ex) {failureCause = ex;throw ex;}catch (Throwable ex) {failureCause = ex;throw new NestedServletException("Request processing failed", ex);}finally {resetContextHolders(request, previousLocaleContext, previousAttributes);if (requestAttributes != null) {requestAttributes.requestCompleted();}if (logger.isDebugEnabled()) {if (failureCause != null) {this.logger.debug("Could not complete request", failureCause);}else {if (asyncManager.isConcurrentHandlingStarted()) {logger.debug("Leaving response open for concurrent processing");}else {this.logger.debug("Successfully completed request");}}}publishRequestHandledEvent(request, response, startTime, failureCause);}}

(5)FrameworkServlet中的doService方法(该方法为抽象方法,有自类具体实现) 所以processRequest为模板模式的实现

protected abstract void doService(HttpServletRequest request, HttpServletResponse response)throws Exception;

(6)我们看上面的类图,FrameworkServlet的自类为DispatcherServlet(饶了半天终于到了我们的DispatcherServlet)

@Overrideprotected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {if (logger.isDebugEnabled()) {String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");}// Keep a snapshot of the request attributes in case of an include,// to be able to restore the original attributes after the include.Map<String, Object> attributesSnapshot = null;if (WebUtils.isIncludeRequest(request)) {attributesSnapshot = new HashMap<String, Object>();Enumeration<?> attrNames = request.getAttributeNames();while (attrNames.hasMoreElements()) {String attrName = (String) attrNames.nextElement();if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {attributesSnapshot.put(attrName, request.getAttribute(attrName));}}}// Make framework objects available to handlers and view objects.
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());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);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);}}}}

(7)我们发现最终的调度过程都是交个DispatcherServlet中的doDispatcher()方法来完成的,重点分析这个方法

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);// Determine handler for the current request.mappedHandler = getHandler(processedRequest);                           //获取HandlerExecutionChain,在HandlerExecutionChain中包含了我们的Controller以及拦截器if (mappedHandler == null || mappedHandler.getHandler() == null) {noHandlerFound(processedRequest, response);return;                                    //如果找不到执行方法则退出}// Determine handler adapter for the current request.HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());       //通过我们的Handler来找到HandlerAdpter(处理器执行器)// 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 (logger.isDebugEnabled()) {logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);}if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {return;}}if (!mappedHandler.applyPreHandle(processedRequest, response)) {     //执行拦截器的preHadnle()方法return;}// Actually invoke the handler.mv = ha.handle(processedRequest, response, mappedHandler.getHandler());    //执行具体的Controller中的方法,得到一个ModelAndView对象if (asyncManager.isConcurrentHandlingStarted()) {return;}applyDefaultViewName(processedRequest, mv);               mappedHandler.applyPostHandle(processedRequest, response, mv);     //执行拦截器的postHandler方法}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 afterCompletionif (mappedHandler != null) {mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);}}else {// Clean up any resources used by a multipart request.if (multipartRequestParsed) {cleanupMultipart(processedRequest);}}}}

这样DispatcherServlet的一次请求过程就完成了(当然这里只是粗略的解析了一下执行流程,之后再去看源码不断的细化)

转载于:https://www.cnblogs.com/liwangcai/p/10743943.html

springMvc的执行流程(源码分析)相关推荐

  1. yaf php源码,PHP-Yaf执行流程-源码分析

    介绍 Yaf框架是通过PHP扩展实现的一种PHP MVC开发框架,因为Yaf框架是PHP扩展实现的,所以性能非常高,而且通过阅读源码可以深入的了解框架内部实现细节和一些优秀的扩展开发技巧,但是学习Ya ...

  2. 跟随一笔交易来看以太坊c++客户端源码执行流程 / 源码分析

    本文初步分析了一个交易在以太坊内部的处理流程,涉及到交易的接收,检查,执行,同步,区块的构建以及挖矿,结合前面一篇基于黄皮书的理解总结,对以太坊有了更多的认识.因为主要的工作在c++层面,所以这里以c ...

  3. spring源码分析第四天------springmvc核心原理及源码分析

    spring源码分析第四天------springmvc核心原理及源码分析 1.基础知识普及 2. SpringMVC请求流程 3.SpringMVC代码流程 4.springMVC源码分析 4.1 ...

  4. 【Java 并发编程】线程池机制 ( 线程池执行任务细节分析 | 线程池执行 execute 源码分析 | 先创建核心线程 | 再放入阻塞队列 | 最后创建非核心线程 )

    文章目录 一.线程池执行任务细节分析 二.线程池执行 execute 源码分析 一.线程池执行任务细节分析 线程池执行细节分析 : 核心线程数 101010 , 最大小成熟 202020 , 非核心线 ...

  5. kettle ftp下载插件,job ftp下载执行结果源码分析

    文章目录 kettle ftp job下载插件执行结果源码分析 问题背景 源码分析 思考: 自己开发的kettle job插件,可以往result中填入我特定的 java成员变量吗? 思路1:继承Re ...

  6. spark DAGScheduler、TaskSchedule、Executor执行task源码分析

    摘要 spark的调度一直是我想搞清楚的东西,以及有向无环图的生成过程.task的调度.rdd的延迟执行是怎么发生的和如何完成的,还要就是RDD的compute都是在executor的哪个阶段调用和执 ...

  7. 【ElasticSearch】Es 启动流程 初始化流程 源码分析

    文章目录 1.概述 1.1 核心类 2. 主要流程 2.1 主方法 2.1.1 关闭过程分析 2.2 execute 方法 2.3 Bootstrap.init 2.4 INSTANCE.setup方 ...

  8. 【ElasticSearch】Es 启动流程 源码分析

    文章目录 1. 概述 2. start方法 2.1 启动生命周期相关的组件 2.2 启动IndicesService 2.3 IndicesClusterStateService启动 2.4 Snap ...

  9. DRF基本使用及执行流程分析 | APIView源码分析

    DRF基本使用及执行流程分析 介绍: # 使用的都是CBV的方式 ,继承的类为drf提供的类(提供的类很多) # 这里目前继承使用APIView类 # 因为APIView是所有类的基类,其他类可能拓展 ...

最新文章

  1. 2021-01-24过去十年十大AI研究热点,分别为深度神经网络、特征抽取、图像分类、目标检测、语义分割、表示学习、生成对抗网络、语义网络、协同过滤和机器翻译。
  2. 对gridview中的一些操作。
  3. 23、Java Swing JTree:树组件
  4. 猛增 174K Star!前端最流行的 10 大顶级开源项目!
  5. Flex itemRenderer 内联渲染器
  6. POJ 2115 C Looooops
  7. debug the very first SAP Fiori application -Jerry的第一个SAP ui5应用调试经过
  8. subline3插件html,Sublime Text3与html的插件
  9. 数字图像处理 空间域锐化 MATLAB实验
  10. Python入门--二重循环中的continue和break
  11. 用C#获取当前的路径
  12. 对象的序列化与反序列化Demo
  13. (13) IFC格式说明 (Industry Foundation Class)
  14. Win10无法调节亮度解决方法
  15. 2009年我国报刊发行创新的五个关键词
  16. python股票分布图_Python股票成交价格分布图(二)
  17. Vue 图片验证码实现【blob、base64】
  18. 服务器更换不同型号的硬盘,服务器更换不同硬盘
  19. 回车和换行,以及不同软件对敲回车键的操作
  20. Oracle ERP 常用查询:R12客户表

热门文章

  1. Merge into 详细介绍
  2. windows下定期清理超过一定时间的文件
  3. IBM AIX JFS 数据恢复记录(暂)
  4. C语言利用循环判断大月小月,对大月和小月进行判断
  5. 化浆池是什么东西_头次见聪明人在阳台上砌洗衣池,开始被人笑话,装完都跟着学...
  6. 好分数a1a5_好分数怎么查看班级排名 七年级学生成绩查询
  7. C++读取txt文件
  8. 怎样理解雷达的相参与非相参
  9. ADC的有效位数与有效分辨率的区别
  10. 矩阵推导后注意力机制居然是这样