SpringMVC框架业务流程源码分析学习笔记【JAVA核心】

1.SpringMVC框架是什么?遵循java web什么规范?

SpringMVC是一个基于Spring生态圈之上封装的一个处理web层请求的半封装框架。

那什么叫半封装框架?

半封装指的SpringMVC是基于servlet处理web层这一技术体系的扩展与延伸——

(1)基于servlet的体系,执行servlet规范,容器当中可以无缝整合

(2)基于spring生态圈的,那么它使用spring资源非常容易

SpringMVC遵循sun公司制定的Java web规范——servlet规范。servlet规范定义了web层的请求处理规范,主要涉及以下几个方法:

package javax.servlet;

import java.io.IOException;
/**
 * Defines methods that all servlets must implement.
 * /
public interface Servlet {
    void init(ServletConfig config) throws ServletException;

    ServletConfig getServletConfig();

    void service(ServletRequest req, ServletResponse res) throws ServletException, IOException;

    String getServletInfo();

    void destroy();
}

从继承图来看,也能明显看出SpringMVC实现了servlet规范。GenericServlet与HttpServlet是Sun公司定义的,从HTTPServletBean开始为SpringMVC框架层。

SpringMVC框架业务流程源码分析学习笔记【JAVA核心】_第1张图片

2.何为SpringMVC上下文(环境支持)?

上下文就是Bean Container:bean的容器技术就算上下文,特别是bean的依赖注入 IOC。

启动项目前需要启动web容器——

SpringMVC框架业务流程源码分析学习笔记【JAVA核心】_第2张图片

SpringMVC框架业务流程源码分析学习笔记【JAVA核心】_第3张图片

监听外部配置文件有没有加载进来,加载后成为Spring的根上下文——>实际上就是提供基础底层的bean的组件


3.SpringMVC如何无缝的和web容器结合的?

springMVC实现了servlet,其本质上就是一个servlet服务

web容器是在web.xml当中挂servlet服务的


    SpringMVC
    org.springframework.web.servlet.DispatcherServlet
    1


    dispatcher
    *.do

那web容器是如何知道按照什么样的规范解读部署在其内部的servlet服务的?

答案还是servlet规范——负责解读部署的项目的web容器,其内部早就植入了servlet规范,以Tomcat为例:

SpringMVC框架业务流程源码分析学习笔记【JAVA核心】_第4张图片

如上图所示:在Apache-Tomcat中已经有了servlet规范
下图是无缝结合的场景——《SpringMVC在Tomcat当中是如何工作?》

SpringMVC框架业务流程源码分析学习笔记【JAVA核心】_第5张图片

Tomcat接受了http请求,内部环境就是一个servlet环境,因为其内部依赖了servlet规范。执行的第一步就是init模块,初始化的时候会读取web.xml中的文件信息。何以见得?我们看一下源码:

SpringMVC框架业务流程源码分析学习笔记【JAVA核心】_第6张图片

GenericServlet中的init方法读取了配置信息,会调用SpringMVC框架中子类HTTPServletBean中重写的初始化方法init(Config),上图中的read会读取servletConfig。

4.SpringMVC框架处理http请求的业务流程

Tomcat收到http请求

4.1 第一步

调用Sun框架中的接口方法:javax.servlet.Servlet#service(ServletRequest req, ServletResponse res)方法

4.2 第二步

调用接口具体实现类方法——org.springframework.web.servlet.FrameworkServlet#service()方法

	/**
	 * Override the parent class implementation in order to intercept PATCH
	 * requests.
	 */
	@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		String method = request.getMethod();
		if (method.equalsIgnoreCase(RequestMethod.PATCH.name())) {
			processRequest(request, response);
		}
		else {
			super.service(request, response);
		}
	}

注释写的很清楚,重写该方法是为了拦截PATCH请求,这个PATCH请求是SpringMVC在Sun公司的基础上增加的一个请求类型

public enum RequestMethod {

	GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE

}

4.3 第三步

除了PATCH请求的其它方法都调用了父类(Sun框架)javax.servlet.http.HttpServlet中的service方法

SpringMVC框架业务流程源码分析学习笔记【JAVA核心】_第7张图片

判定请求方法类型,然后派发请求给各个处理函数

特别对GET方法进行了IMS(If-Modified-Since)比较

 if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // 服务器不支持IMS,直接开始处理逻辑
                doGet(req, resp);
            } else {  //服务器支持IMS比较,那就先判断
                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)) {
                    // 服务端资源有更新
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {//服务端资源无更新
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }

        } 

如果你不了解IMS的概念,请阅读该博文HTTP的请求头标签 If-Modified-Since与Last-Modified

4.4 第四步

上面调用的各个处理函数org.springframework.web.servlet.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);
		}
		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, startTime, failureCause);
		}
	}

4.5 第五步

调用org.springframework.web.servlet.FrameworkServlet#processRequest()中的doService()方法,该抽象方法被DispatchServlet实现,因此最终调用org.springframework.web.servlet.DispatchServlet#doService()(源代码分析待续)

protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		if (logger.isDebugEnabled()) {
			String requestUri = urlPathHelper.getRequestUri(request);
			String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
			logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
					" processing " + request.getMethod() + " request for [" + requestUri + "]");
		}

		// 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)) {
			logger.debug("Taking snapshot of request attributes before include");
			attributesSnapshot = new HashMap();
			Enumeration attrNames = request.getAttributeNames();
			while (attrNames.hasMoreElements()) {
				String attrName = (String) attrNames.nextElement();
				if (this.cleanupAfterInclude || attrName.startsWith("org.springframework.web.servlet")) {
					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()) {
				return;
			}
			// Restore the original attribute snapshot, in case of an include.
			if (attributesSnapshot != null) {
				restoreAttributesAfterInclude(request, attributesSnapshot);
			}
		}
	}

其中又调用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.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				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()) {
						String requestUri = urlPathHelper.getRequestUri(request);
						logger.debug("Last-Modified value for [" + requestUri + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}

				try {
					// Actually invoke the handler.
					mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
				}
				finally {
					if (asyncManager.isConcurrentHandlingStarted()) {
						return;
					}
				}

				applyDefaultViewName(request, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
		}
		catch (Exception ex) {
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Error err) {
			triggerAfterCompletionWithError(processedRequest, response, mappedHandler, err);
		}
		finally {
			if (asyncManager.isConcurrentHandlingStarted()) {
				// Instead of postHandle and afterCompletion
				mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				return;
			}
			// Clean up any resources used by a multipart request.
			if (multipartRequestParsed) {
				cleanupMultipart(processedRequest);
			}
		}
	}

业务流程图解析如下——

SpringMVC框架业务流程源码分析学习笔记【JAVA核心】_第8张图片

5.手写SpringMVC

具体请参见另一篇博文《手写注解实现SpringMVC底层原理【JAVA核心】》


你可能感兴趣的:(JAVA核心,SpringMVC)