Spring源码学习27

Spring处理请求方法委托给了processRequest(request,response);

@Override
	protected final void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

1.FrameworkServlet.processRequest(HttpServletRequest request,HttpServletResponse response);

/**
	 * 处理此请求,无论结果如何都发布事件。
	 * <p>实际的事件处理由{@link #doService}模板方法执行。
	 */
	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//记录当前时间
		long startTime = System.currentTimeMillis();
		Throwable failureCause = null;
		//返回当前线程的LocaleContext
		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
		//构建当前语言环境的上下文
		LocaleContext localeContext = buildLocaleContext(request);
		//返回当前线程绑定的RequestAttributes
		RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
		//获取request请求的WebAsyncManager或者new一个
		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
		//绑定localeContext和requestAttributes到当前线程上
		//为什么绑定到当前线程上???
		//在spring mvc中,为了随时都能取到当前请求的request对象,可以通过RequestContextHolder
		// 的静态方法getRequestAttributes()获取Request相关的变量,如request, response等。
		// LocaleContext当然效果同理
		initContextHolders(request, localeContext, requestAttributes);
		try {
			//委托DipsatcherServlet实现
			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 {
			//重新绑定之前的localeContext和requestAttributes到线程上
			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);
		}
	}

主要就是构造当前request请求的LocaleContext和ServletRequestAttributes对象通过initContextHolders(request, localeContext, requestAttributes);方法绑定到线程,为了随时都能取到当前请求的request对象,可以通过RequestContextHolder 的静态方法getRequestAttributes()获取Request相关的变量,如request, response等。 // LocaleContext当然效果同理;然后方法委托给了doService(request,response);恢复线程先前绑定的LocaleContext和ServletRequestAttributes对象,最后就是发布请求处理处理完成的事件

private void publishRequestHandledEvent(
			HttpServletRequest request, HttpServletResponse response, long startTime, Throwable failureCause) {
		//请求结束后发布个事件
		if (this.publishEvents) {
			// Whether or not we succeeded, publish an event.
			long processingTime = System.currentTimeMillis() - startTime;
			// 获取状态码
			int statusCode = (responseGetStatusAvailable ? response.getStatus() : -1);
			// 发布事件
			this.webApplicationContext.publishEvent(
					new ServletRequestHandledEvent(this,
							request.getRequestURI(), request.getRemoteAddr(),
							request.getMethod(), getServletConfig().getServletName(),
							WebUtils.getSessionId(request), getUsernameForRequest(request),
							processingTime, failureCause, statusCode));
		}
	}

2.使用监听器监听ServletRequestHandledEvent事件

定义ServletRequestHandledEventListener实现ApplicationListener

/**
 * @author 周宁
 * @Date 2019-08-20 19:18
 */
public class ServletRequestHandledEventListener implements ApplicationListener<ServletRequestHandledEvent> {
    @Override
    public void onApplicationEvent(ServletRequestHandledEvent event) {
        System.out.println(event.getRequestUrl());
    }
}

在applicationContext.xml中配置ServletRequestHandledEventListener

<bean id="servletRequestHandledEventListener" class="org.springframework.studymvc.event.ServletRequestHandledEventListener"/>

3.DispatcherServlet.doService(HttpServletRequest request,HttpServletResponse response);

 /**
     * 将DispatcherServlet特定的请求属性和委托公开给{@link #doDispatch}以进行实际调度。
     */
    @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.

        // 在包含requeset请求的情况下保留请求属性快照
        // 能够在包含之后恢复原始属性。
        Map<String, Object> attributesSnapshot = null;
        if (WebUtils.isIncludeRequest(request)) {
            //request请求快照
            attributesSnapshot = new HashMap<String, Object>();
            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的上下文
        request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
        // 设置request的国际化
        request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
        // 设置request的theme属性
        request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
        // 获取ThemeSource
        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()) {
                // 如果是include,则还原原始属性快照。
                if (attributesSnapshot != null) {
                    restoreAttributesAfterInclude(request, attributesSnapshot);
                }
            }
        }
    }

该方法主要是给当前request对象添加一系列的attribute;我们后面可以通过request.getAttribute(attributeName)获取到啦;

这里主要难理解的是WebUtils.isIncludeRequest(request)这里的方法,我们需要知道的是jsp的本质就是servlet

<jsp:incluede page="index.jsp"/>

这条指令是指在一个页面中嵌套了另一个页面,那么我们知道JSP在运行期间是会被编译成相应的Servlet类来运行的,所以在Servlet中也会有类似的功能和调用语法,这就是RequestDispatch.include()方法。 那么在一个被别的servlet使用RequestDispatcher的include方法调用过的servlet中,如果它想知道那个调用它的servlet的上下文信息该怎么办呢,那就可以通过request中的attribute中的如下属性获取: 

javax.servlet.include.request_uri

javax.servlet.include.context_path

javax.servlet.include.servlet_path

javax.servlet.include.path_info

javax.servlet.include.query_string

4.DispatcherServlet.doDispatch(HttpServletRequest request,HttpServletResponse response);

 /**
     * 处理实际调度到处理程序。
     * <p>处理程序将通过按顺序应用DispatcherServlet的HandlerMappings来获得。
     * 将通过查询servlet安装的HandlerAdapter来获取HandlerAdapter,以找到支持处理程序类的第一个。
     * <p>所有HTTP方法都由此方法处理。 由HandlerAdapters或处理程序自行决定哪些方法可以接受。
     *
     * @param request  current HTTP request
     * @param response current HTTP response
     * @throws Exception in case of any kind of processing failure
     */
    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 {
                //转换当前request为MultipartHttpServletRequest
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);

                // 确定当前请求的处理程序。
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    //如果未找到
                    noHandlerFound(processedRequest, response);
                    return;
                }

                // 确定当前请求的处理程序适配器。
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

                // 处理最后修改的标头,如果处理程序支持。
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                //请求头方法支持last-modified头处理
                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;
                    }
                }
                //应用前置拦截器,前置处理器返回false则程序退出
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }

                // Actually invoke the handler.
                // 实际调用处理器的方法
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
                //7.如果当前请求是并发处理,直接返回
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                //为返回值设定默认视图名,如果当前返回值中不包含视图名的话
                applyDefaultViewName(processedRequest, mv);
                //注册的拦截器的后处理方法应用
                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);
            }
            //请求处理过程的结果呈现
            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()) {
                // 异步请求的条件下触发AsyncHandlerInterceptor.afterConcurrentHandlingStarted方法
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            } else {
                // 清理多部分请求使用的任何资源。
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }

方法主要流程为:

  • a.使用multipartResolver处理文件上传请求的request转换为MultipartHttpServletRequest
  • b.通过我们初始化的handlerMappings获取当前request请求的HandlerExecutionChain(处理程序执行链,由处理程序对象和任何处理程序拦截器组成。)
  • c.HandlerExecutionChain不存在或者里面的处理程序Handler为null,设置适当的HTTP响应状态码
  • d.通过配置的handlerAdapters找到合适的HandlerAdapter
  • e.判断请求是否支持last-modified
  • f.应用注册的HandlerInterceptors的preHandle方法,如果返回false,则停止处理该请求并调用HandlerInterceptors的triggerAfterCompletion方法
  • g.使用HandlerAdapter调用实际的请求处理方法并返回一个ModelAndView对象
  • h.设置视图的默认名称
  • i.应用HandlerInterceptor的postHandle方法
  • j.捕获从a-i过程中的异常并将请求处理的结果呈现出来并最终调用HandlerInterceptors的afterCompletion方法!!!
  • k.如果整个流程出现了异常那么调用HanlderInterceptors的afterCompletion方法
  • l.清楚上传文件使用的任何资源

5.SpringMVC整体流程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值