• DispatcherServlet源码详解


    1.导论

    DispatcherServlet其实就是一个Servlet类,无非就是包装来根据url能够映射找到我们SpringMVC中定义的请求方法。
    在这里插入图片描述

    2.源码分析

    在这里插入图片描述
    这里我们可以看出DispatcherServlet继承FrameworkServlet继承HttpServlet。根据面向基本思想,重写是先走父类,再走子类。所以我们从父类开始分析
    1.首先肯定会走到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);
                } else {
                    long ifModifiedSince;
                    try {
                        ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                    } catch (IllegalArgumentException iae) {
                        // Invalid date header - proceed as if none was set
                        ifModifiedSince = -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);
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64

    2.这里我们从doGet方法进行分析,因为FrameworkServlet继承了HttpServlet,并对doGet方法进行了重写,因此,执行时候执行的是FrameworkServlet中的doGet方法。

    // HttpServlet中
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException
        {
            String protocol = req.getProtocol();
            String msg = lStrings.getString("http.method_get_not_supported");
            if (protocol.endsWith("1.1")) {
                resp.sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED, msg);
            } else {
                resp.sendError(HttpServletResponse.SC_BAD_REQUEST, msg);
            }
        }
    
    // FrameWorkServlet中
    @Override
    protected final void doGet(HttpServletRequest request, HttpServletResponse response)
    		throws ServletException, IOException {
    
    	processRequest(request, response);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    3.然后我们看这里调用了processRequest方法,在processRequest方法中我们看到调用了doService方法

    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);
    		}
    		catch (ServletException | 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);
    		}
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53

    4.在FrameworkServlet中我们可以看到doSercice方法是一个抽象方法,真正的实现在DispatcherServlet中,所以最终执行的doService方法是DispatcherServlet的doService方法

    //FrameworkServlet
    protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
    			throws Exception;
    
    //DispatcherServlet
    @Override
    protected 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<>();
    		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());
    
    	if (this.flashMapManager != null) {
    		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);
    			}
    		}
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55

    4.在doSevice方法中调用了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);
    
    				// Determine handler for the current request.
    				// 1.调用该方法,获得一个handler执行链,也就是我们控制层的方法
    				mappedHandler = getHandler(processedRequest);
    				// 如果没有找到,这时候会抛出一个异常,这也是我们前端页面经常看到的404
    				if (mappedHandler == null) {
    					noHandlerFound(processedRequest, response);
    					return;
    				}
    
    				// Determine handler adapter for the current request.		
    				// 2、根据handler执行链中的handler,找到相应的适配器
    				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 (logger.isDebugEnabled()) {
    						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
    					}
    					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
    						return;
    					}
    				}
    				// 3.执行拦截器前置方法,mappedHandler(handler执行链)
    				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
    					return;
    				}
    
    				// Actually invoke the handler.
    				// 4.执行目标方法
    				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
    
    				if (asyncManager.isConcurrentHandlingStarted()) {
    					return;
    				}
    
    				applyDefaultViewName(processedRequest, mv);
    				// 5.执行后置方法 
    				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);
    			}
    			// 6.渲染页面
    			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
    		}
    		// 7.执行拦截器afterCompletion方法
    		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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    // 1.调用getHandler方法,我们可以看到从handlerMapping中获得一个handler执行链
    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
    	if (this.handlerMappings != null) {
    		for (HandlerMapping hm : this.handlerMappings) {
    			if (logger.isTraceEnabled()) {
    				logger.trace(
    						"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
    			}
    			HandlerExecutionChain handler = hm.getHandler(request);
    			if (handler != null) {
    				return handler;
    			}
    		}
    	}
    	return null;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    3.总结

    HttpServlet中的service方法,判断请求,如果是get请求->最终执行的是FrameworkServlet中的doGet方法->最终执行DispatcherServlet中的doService方法->执行doDispatch方法(核心方法
    1.执行doDispatch(下面步骤都在doDispatch方法中)
    2.调用getHandler方法获取目标的方法,也就是请求url映射路径对应的控制层具体的方法。
    handlerMappings的作用查找控制器位置,比如xml和注解方式
    3.调用getHandlerAdapter获取控制层适配器RequestMappingHandlerAdapter
    4.执行拦截器前置方法preHandle()
    5.执行实际请求目标方法,返回ModelAndView对象
    6.执行拦截器PostHandler()方法
    7.设置渲染视图层内容
    8.执行拦截器afterCompletion方法
    在这里插入图片描述
    *SpringMVC控制层容器初始化
    1.HttpServletBean init()方法
    2.FrameworkServlet initServletBean方法->initWebApplicationContext()
    3.DispatcherServlet onFresh()方法->initStrategies()方法

  • 相关阅读:
    CompletableFuture异步编排(两任务组合——其中一个任务执行)
    图片对比相似度算法标准,图片相似度匹配算法
    北大肖臻老师《区块链技术与应用》系列课程学习笔记[18]以太坊-挖矿算法
    数据结构链表之无头单向循环链表的实现
    【vue2第十章】data数据与组件间通信
    开发板连接WiFi时获取不到ip,且不断的报如下问题
    Hbase regionserver频繁突然挂掉的问题处理
    碳中和数据合集:含中国碳中和政策全集、碳中和论文合集
    Vue 报错error:0308010C:digital envelope routines::unsupported
    Flask框架中Jinja2模板中测试器(判断值类型)
  • 原文地址:https://blog.csdn.net/qq_46517733/article/details/126676790