栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

SpringMVC执行流程(含部分源码解析)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

SpringMVC执行流程(含部分源码解析)

SpringMVC 执行流程

SpringMVC 常用组件SpringMVC 初始化过程

初始化 WebApplicationContext(容器初始化)创建 WebApplicationContext(创建容器)DispatcherServlet 初始化策略 DispatcherServlet 调用组件处理请求

HttpServlet 部分源码processRequest()doService()doDispatch()processDispatchResult() SpringMVC 的执行流程

SpringMVC 常用组件

DispatcherServlet:前端控制器,不需要工程师开发,由框架提供。

作用:统一处理请求和响应,整个流程控制的中心,由它调用其它组件处理用户的请求

HandlerMapping:处理器映射器,不需要工程师开发,由框架提供。

作用:根据请求的 url、method 等信息查找 Handler,即控制器方法

Handler:处理器,需要工程师开发

作用:在 DispatcherServlet 的控制下 Handler 对具体的用户请求进行处理

HandlerAdapter:处理器适配器,不需要工程师开发,由框架提供

作用:通过 HandlerAdapter 对处理器(控制器方法)进行执行

ViewResolver:视图解析器,不需要工程师开发,由框架提供

作用:进行视图解析,得到相应的视图,例如:ThymeleafView、InternalResourceView、RedirectView

View:视图

作用:将模型数据通过页面展示给用户

SpringMVC 初始化过程

DispatcherServlet 本质上是一个 Servlet,所以天然的遵循 Servlet 的生命周期。所以宏观上是 Servlet 生命周期来进行调度。

初始化 WebApplicationContext(容器初始化)

所在类:org.springframework.web.servlet.frameworkServlet

部分源码:

public abstract class frameworkServlet extends HttpServletBean implements ApplicationContextAware {
	@Override
	protected final void initServletBean() throws ServletException {
		getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");
		if (logger.isInfoEnabled()) {
			logger.info("Initializing Servlet '" + getServletName() + "'");
		}
		long startTime = System.currentTimeMillis();

		try {
			// 创建 WebApplicationContext(对SpringMvc容器进行初始化)
			this.webApplicationContext = initWebApplicationContext();
			initframeworkServlet();
		}
		catch (ServletException | RuntimeException ex) {
			logger.error("Context initialization failed", ex);
			throw ex;
		}

		if (logger.isDebugEnabled()) {
			String value = this.enableLoggingRequestDetails ?
					"shown which may lead to unsafe logging of potentially sensitive data" :
					"masked to prevent unsafe logging of potentially sensitive data";
			logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +
					"': request parameters and headers will be " + value);
		}

		if (logger.isInfoEnabled()) {
			logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");
		}
	}
}
创建 WebApplicationContext(创建容器)

所在类:org.springframework.web.servlet.frameworkServlet

部分源码:

public abstract class frameworkServlet extends HttpServletBean implements ApplicationContextAware {
	protected WebApplicationContext initWebApplicationContext() {
		// 通过WebApplicationContextUtils工具类获取当前的WebApplicationContext
		WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		// 第一次执行的时候 webApplicationContext 肯定是等于空的!
		if (this.webApplicationContext != null) {
			// A context instance was injected at construction time -> use it
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				if (!cwac.isActive()) {
					// The context has not yet been refreshed -> provide services such as
					// setting the parent context, setting the application context id, etc
					if (cwac.getParent() == null) {
						// The context instance was injected without an explicit parent -> set
						// the root application context (if any; may be null) as the parent
						cwac.setParent(rootContext);
					}
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		// 如果等于空,则先去查找一遍
		if (wac == null) {
			// No context instance was injected at construction time -> see if one
			// has been registered in the servlet context. If one exists, it is assumed
			// that the parent context (if any) has already been set and that the
			// user has performed any initialization such as setting the context id
			wac = findWebApplicationContext();
		}
		// 如果找不到,则会创建 WebApplicationContext
		if (wac == null) {
			// 创建 WebApplicationContext
			wac = createWebApplicationContext(rootContext);
		}

		if (!this.refreshEventReceived) {
			// Either the context is not a ConfigurableApplicationContext with refresh
			// support or the context injected at construction time had already been
			// refreshed -> trigger initial onRefresh manually here.
			synchronized (this.onRefreshMonitor) {
				// 刷新事件,刷新 WebApplicationContext
				onRefresh(wac);
			}
		}

		if (this.publishContext) {
			// 获取 ServletContext 的属性名
			String attrName = getServletContextAttributeName();
			
			getServletContext().setAttribute(attrName, wac);
		}

		return wac;
	}
	
	// 创建 WebApplicationContext
	protected WebApplicationContext createWebApplicationContext(@Nullable WebApplicationContext parent) {
		return createWebApplicationContext((ApplicationContext) parent);
	}
	
	protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
		Class contextClass = getContextClass();
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException(
					"Fatal initialization error in servlet with name '" + getServletName() +
					"': custom WebApplicationContext class [" + contextClass.getName() +
					"] is not of type ConfigurableWebApplicationContext");
		}
		// 通过反射创建 SpringMVC 的 IOC 容器对象
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

		wac.setEnvironment(getEnvironment());
		// 将 Spring 的IOC容器设置为 SpringMVC 的父容器
		wac.setParent(parent);
		String configLocation = getContextConfigLocation();
		if (configLocation != null) {
			wac.setConfigLocation(configLocation);
		}
		configureAndRefreshWebApplicationContext(wac);

		return wac;
	}
    
    // 刷新 WebApplicationContext
	protected void onRefresh(ApplicationContext context) {
		// 让子类(DispatcherServlet)进行操作
	}
	
	// 获取 ServletContext 的属性名
	public static final String SERVLET_CONTEXT_PREFIX = frameworkServlet.class.getName() + ".CONTEXT.";
	
	public String getServletContextAttributeName() {
		return SERVLET_CONTEXT_PREFIX + getServletName();
	}
}
DispatcherServlet 初始化策略

所在类:org.springframework.web.servlet.DispatcherServlet

frameworkServlet 创建 WebApplicationContext 后,刷新容器,调用 onRefresh(wac),此方法在 DispatcherServlet 中进行了重写,调用了 initStrategies(context) 方法,初始化策略,即初始化 DispatcherServlet 的各个组件。

部分源码:

public class DispatcherServlet extends frameworkServlet {	
	@Override
	protected void onRefresh(ApplicationContext context) {
		// 初始化策略
		initStrategies(context);
	}

	
	protected void initStrategies(ApplicationContext context) {
		// 初始化文件上传解析器
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		// 初始化处理器映射器(通过它可以将请求和控制器方法创建映射关系)
		initHandlerMappings(context);
		// 初始化处理器适配器(通过它来根据请求调用对应的控制器方法)
		initHandlerAdapters(context);
		// 初始化异常处理器
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		// 初始化视图解析器
		initViewResolvers(context);
		initFlashMapManager(context);
	}
}
DispatcherServlet 调用组件处理请求

如果图看不懂的话可结合下面的源码一起理解,最好是自己打开代码看一下

HttpServlet 部分源码

该类将 service 方法进行了重载,把 ServletRequest 转换成了 HttpServletRequest,然后对不同的请求方式进行了不同的处理。在 frameworkServlet 类中重写了所有处理各种请求方式的方法:doXxx

public abstract class HttpServlet extends GenericServlet {
	@Override
    public void service(ServletRequest req, ServletResponse res)
        throws ServletException, IOException
    {
        HttpServletRequest  request;
        HttpServletResponse response;
        
        if (!(req instanceof HttpServletRequest &&
                res instanceof HttpServletResponse)) {
            throw new ServletException("non-HTTP request or response");
        }

		// 将 ServletRequest 转换为 HttpServletRequest
        request = (HttpServletRequest) req;
		// 将 ServletResponse 转换为 HttpServletResponse
        response = (HttpServletResponse) res;

        service(request, response);
    }
	
	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 = req.getDateHeader(HEADER_IFMODSINCE);
                if (ifModifiedSince < lastModified) {
                    // 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);
        }
    }
}
processRequest()

frameworkServlet 重写 HttpServlet 中的 service() 和 doXxx(),这些方法中调用了 processRequest(request, response)

所在类:org.springframework.web.servlet.frameworkServlet

部分源码:

public abstract class frameworkServlet extends HttpServletBean implements ApplicationContextAware {
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		// 获取请求方式
		HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
		// 如果请求方式为 PATCH 或 为空
		if (httpMethod == HttpMethod.PATCH || httpMethod == null) {
			processRequest(request, response);
		}
		else {
			// 虽然这里调用的父类的 service() 方法,但是在当前类中对请求处理进行了重写,所以最后使用的还是当前类中的方法进行处理的
			super.service(request, response);
		}
	}
	
	// 处理 GET 请求
	@Override
	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

	// 处理 Post 请求
	@Override
	protected final void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

	// 处理 Put 请求
	@Override
	protected final void doPut(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

	// 处理 Delete 请求
	@Override
	protected final void doDelete(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}
	
	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()是一个抽象方法,在 DispatcherServlet 中进行了重写
			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();
			}
			logResult(request, response, failureCause, asyncManager);
			publishRequestHandledEvent(request, response, startTime, failureCause);
		}
	}
	
	// 该方法是一个抽象方法,所以要看它的子类实现
	protected abstract void doService(HttpServletRequest request, HttpServletResponse response)
			throws Exception;
}
doService()

所在类:org.springframework.web.servlet.DispatcherServlet

public class DispatcherServlet extends frameworkServlet {	
	@Override
	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		logRequest(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 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);
		}

		RequestPath requestPath = null;
		if (this.parseRequestPath && !ServletRequestPathUtils.hasParsedRequestPath(request)) {
			requestPath = ServletRequestPathUtils.parseAndCache(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);
				}
			}
			if (requestPath != null) {
				ServletRequestPathUtils.clearParsedRequestPath(request);
			}
		}
	}
}
doDispatch()

所在类:org.springframework.web.servlet.DispatcherServlet

public class DispatcherServlet extends frameworkServlet {
	// 处理请求和响应
	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
				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;
					}
				}

				// 调用拦截器的 preHandle() 方法(感兴趣可点进去看一下applyPreHandle()方法的细节)
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				// 执行处理器适配器调用的控制器方法,最终得到一个 ModelAndView 对象
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
				// 调用拦截器的 postHandle() 方法(感兴趣可点进去看一下applyPostHandle()方法的细节)
				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);
			}
			// 处理 ModelAndView(解析模型数据和渲染视图)
			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);
				}
			}
		}
	}
}

这个方法是一个比较关键的方法

processDispatchResult()

所在类:org.springframework.web.servlet.DispatcherServlet

public class DispatcherServlet extends frameworkServlet {	
	// 解析模型数据和渲染视图
	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) {
			// 调用拦截器的 afterCompletion() 方法(感兴趣可点进去看一下triggerAfterCompletion()方法的细节)
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}
}
SpringMVC 的执行流程

    用户向服务器发送请求,请求被 SpringMVC 前端控制器 DispatcherServlet 捕获。

    DispatcherServlet 对请求 URL 进行解析,得到请求资源标识符(URI),判断请求 URI 对应的映射是否存在

    如果不存在

    再判断是否配置了 mvc:default-servlet-handler (开放对静态资源的访问)如果没配置,则控制台报映射查找不到,客户端展示 404 错误如果有配置,则访问目标资源(一般为静态资源,如:JS、CSS、HTML),找不到客户端也会展示 404 错误

    存在则执行下面的流程

    根据该 URI,调用 HandlerMapping 获得该 Handler 配置的所有相关的对象(包括 Handler 对象以及 Handler 对象对应的拦截器),最后以 HandlerExecutionChain (调用链,可看源码)执行链对象的形式返回。

    Handler 指的就是控制器方法

    DispatcherServlet 根据获得的 Handler,选择一个合适的 HandlerAdapter(处理器适配器)。

    如果成功获得 HandlerAdapter,此时将开始执行拦截器的 preHandler(…) 方法(正向执行)

    提取 Request 中的模型数据,填充 Handler 入参,开始执行 Handler(Controller) 方法,处理请求。 在填充 Handler 的入参过程中,根据你的配置,Spring 将帮你做一些额外的工作:

    HttpMessageConveter: 将请求消息(如 Json、xml 等数据)转换成一个对象,将对象转换为指定的响应信息数据转换:对请求消息进行数据转换。如 String 转换成 Integer、Double 等数据格式化:对请求消息进行数据格式化。如将字符串转换成格式化数字或格式化日期等数据验证: 验证数据的有效性(长度、格式等),验证结果存储到 BindingResult 或 Error 中

    Handler 执行完成后,向 DispatcherServlet 返回一个 ModelAndView 对象。

    此时将开始执行拦截器的 postHandle(…) 方法(逆向执行)。

    根据返回的 ModelAndView(此时会判断是否存在异常:如果存在异常,则执行 HandlerExceptionResolver 进行异常处理)选择一个适合的 ViewResolver 进行视图解析,根据 Model 和 View 来渲染视图。

    渲染视图完毕执行拦截器的 afterCompletion(…) 方法(逆向执行)。

    将渲染结果返回给客户端。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/716804.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号