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);
        }
    }

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);
}

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);
		}
	}

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);
			}
		}
	}
}

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.调用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;
}

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()方法

  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: dispatcherservlet是Spring MVC框架的核心组件之一,负责接收所有的客户端请求,并将其分发给相应的处理器方法进行处理。 首先,dispatcherservlet作为一个前端控制器,接收到所有的请求,并根据请求的URL将其映射到具体的处理器方法上。它通过HandlerMapping来完成URL到方法的映射,可以根据不同的URL配置不同的映射规则。 其次,dispatcherservlet将请求分发给对应的处理器方法进行处理。处理器方法是真正执行业务逻辑的地方,它们是由@Controller注解标记的方法。在处理器方法中,可以获取客户端传递过来的参数,并根据业务需求处理这些参数。处理器方法还可以返回相应的结果,例如将数据模型返回给视图进行渲染。 最后,dispatcherservlet将处理结果返回给客户端。它通过ViewResolver来找到对应的视图,将数据模型传递给视图进行渲染,并将渲染后的内容返回给客户端。视图可以是HTML页面、JSON数据等多种形式,根据业务需求进行配置。 总之,dispatcherservlet在Spring MVC框架中起到了非常重要的作用。它负责接收客户端请求,并将请求分发给对应的处理器方法进行处理。通过配置不同的映射规则和视图解析器,我们可以实现灵活的请求处理和响应结果的渲染。通过学习和理解dispatcherservlet的工作原理,可以更好地使用和理解Spring MVC框架。 ### 回答2: Spring MVC是一个基于Java的Web应用开发框架,其中的DispatchServlet是Spring MVC的核心组件之一。DispatchServlet是一个Servlet类,用于接收HTTP请求并将其分发给不同的Controller进行处理。 在Spring MVC中,DispatchServlet是由Web容器(例如Tomcat)加载并初始化的。当客户端发送HTTP请求时,Web容器将请求发送到DispatchServlet,DispatchServlet通过URL映射来确定将请求分发给哪一个Controller进行处理。URL映射是通过配置文件或注解来实现的,可以根据请求的URL路径、请求参数等来进行匹配。 DispatchServlet将请求分发给Controller后,Controller会根据请求的业务逻辑进行处理,并生成相应的响应。在处理请求的过程中,Controller可以通过注解来获取请求的参数、请求头等信息,并进行相应的处理。处理完成后,Controller会返回一个ModelAndView对象,其中包含了响应的数据和视图名。 DispatchServlet在接收到Controller返回的ModelAndView后,会将数据传递给ViewResolver来解析视图名并找到相应的视图模板。ViewResolver负责将响应的数据以及视图模板进行解析和渲染,最终生成一个HTML响应,并将其返回给客户端。 除了处理请求分发和视图解析外,DispatchServlet还负责处理异常和拦截器等功能。当请求处理过程中发生异常时,DispatchServlet会将异常信息进行捕获并交给异常处理器进行处理。拦截器可以用于在请求到达Controller之前或之后进行一些预处理或后处理操作,例如登录拦截、权限验证等。 总之,DispatchServlet是Spring MVC框架中的核心组件之一,负责接收并分发HTTP请求,处理请求的分发、视图解析、异常处理和拦截等功能,是Spring MVC框架实现Web应用开发的重要部分。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Listen·Rain

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值