SpringMVC源码剖析(二)SpringMVC是如何处理请求的

分析思路:

肯定是3层Servlet如何处理以及每层具体做了什么,最后分析最重要的一个方法doDispatch

回顾一下Servlet的请求处理过程  在HttpServlet中的service方法根据不同的动作分发了不同7种的请求


HttpServletBean

作用主要参加了创建工作,并没有涉及到请求的处理   这一步它没有具体处理请求


FrameworkServlet

在该类中重写了service   doXXX(除了doHead外的所有方法)

并且在service方法中增加了PATCH类型的处理  其他请求默认给父类处理

而doGet  doPost  doDelete  doPut都是自己处理  所有自己需要处理的请求都交给了processRequest方法统一处理

protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		if (RequestMethod.PATCH.name().equalsIgnoreCase(request.getMethod())) {
			processRequest(request, response);
		}
		else {
			super.service(request, response);
		}
	}
我们发现HttpServlet是按不同请求类型路由到不同的方法处理  而这里相反

它采用另外一种方式处理将不同类型的请求处理用不同的Handler处理  这里后面再讲



思考???为何还不在service中覆盖service


下来分析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);
		}
		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);
		}
	}

我们发现它调用了doService模板方法,其他的处理逻辑日后再补充


我们总结一下在service中添加了对PATCH的处理,并将所有需要自己处理的请求集中到了processRequest方法进行统一处理

然后就是processRequest交给了doService处理  另外是对使用当前request获取到的LocaleContext和RequestAttributes进行了保存,以及处理完之后的恢复,在最后发布了ServletRequestHandlerEvent事件


我们这事来分析doService

	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
        //这里将日志省略

        // Keep a snapshot of the request attributes in case of an include,
        // to be able to restore the original attributes after the include.
              //当include请求满足对request的Attribute做快照备份
        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("org.springframework.web.servlet")) {
                    attributesSnapshot.put(attrName, request.getAttribute(attrName));
                }
            }
        }
              //对request限制一些属性
        // 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.//还原request的快照
                if (attributesSnapshot != null) {
                    restoreAttributesAfterInclude(request, attributesSnapshot);
                }
            }
        }
    }
		

好像有点复杂  看了一脸懵逼

但是简单的比如它是调用doDispatch

而在调用doDispatch前做了一些事情

首先判断是不是include请求  如果是则对request的Attribute做个快照备份 等doDispatch之后(如果不是异步请求且未完成)进行还原

在做完之后对request设置一些属性


具体设置了什么呢

// 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());
设置了4个属性webApplicationContext  ,localeResolver,themeResolver,themeSource在之后介绍的handler和view中需要使用到时候在分析

后3个属性和flashMap相关,主要用于Redirect转发时参数的传递  这里我没看懂

关于flashMap的使用我后面再更新  现在还不太会


整理一下 doService对request设置了一些属性  如果是include请求还要对request当前的属性做快照备份 并在处理结束后恢复  最后把请求给了doDispatch


再来看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, false);
				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()) {
						logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
					}
					if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
						return;
					}
				}

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

				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				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
				if (mappedHandler != null) {
					mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
				}
			}
			else {
				// Clean up any resources used by a multipart request.
				if (multipartRequestParsed) {
					cleanupMultipart(processedRequest);
				}
			}
		}
	}
是不是有点长啊 看着费力气

我们抓住重要的看  看核心语句

	mappedHandler = getHandler(processedRequest, false);
	HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
	mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
	processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);

核心代码4句 做了四件事

1.根据request找到Handler

2.根据Handler找到相应的HandlerAdapter

3.用HandlerAdapter处理Handler

4.调用processDispatchResult方法处理上面处理之后的结果(包括找到View并渲染输出给用户)


关于HandlerMapping,Handler,HandlerAdapter区别

后面再细讲啊

通俗一点理解

Handler是用来干活的工具 HandlerMapping是根据干的活找相应的工具 HandlerAdapter是使用工具干活的人

在SpringMVC中的9大组件HandlerAdapter最复杂

除此之外viewResolver是根据 需要查找view的 view是展示数据的


现在就很好理解他们的逻辑了

根据HandlerMapping找到干活的Handler  找到使用Handler的HandlerAdapter  让个HandlerAdapter使用Handler干活  干完活后将结果提交上去(通过view展示给用户)


然后在回到doDispatch分析还是很复杂

doDispatch可以大体分两部分  处理请求渲染页面

先看它定义的变量

此处省略1万字 太难了  ....................分析不了  以后再说

我们可以看到它是在顶层设计好分配给不同的组件去实现的


这篇文章只是提供了处理请求的大概思路具体的后续再更新


欢迎关注我的个人订阅号,我会推送更好的文章给大家

SpringMVC源码剖析(二)SpringMVC是如何处理请求的_第1张图片

你可能感兴趣的:(springMVC,SpringMvc体系源码分析,spring,mvc)