天天看点

springmvc(二) springmvc的大脑—DispatcherServlet源码小解DispatcherServlet的作用将请求交予springmvc处理的过程

DispatcherServlet的作用

springmvc(二) springmvc的大脑—DispatcherServlet源码小解DispatcherServlet的作用将请求交予springmvc处理的过程

上面是网上找的一张图,大概可以说明DispatcherServlet在整个数据流中起到的作用。

  • 初始化springmvc所需的组件
  • 截获请求,交给springmvc框架处理
  • 协调组件处理请求

本文不注重细节的分析,只简单分析下是如何截获http请求和如何协调组件进行处理http请求

将请求交予springmvc处理的过程

首先看下DispatcherServlet的继承关系:

springmvc(二) springmvc的大脑—DispatcherServlet源码小解DispatcherServlet的作用将请求交予springmvc处理的过程

HttpServlet我们都很熟悉了,对Http请求做了封装。

看下以下几个类:

HttpServletBean

public abstract class HttpServletBean extends HttpServlet implements EnvironmentCapable, EnvironmentAware
           

这个类除了继承了HttpServlet,还实现了两个接口,EnvironmentCapable和EnvironmentAware,说明这个类及其子类拥有了获取和设置运行时Environment的能力。

同时,这个类实现了init方法,在servlet初始化时,用来初始化bean。

public final void init() throws ServletException {
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing servlet '" + getServletName() + "'");
		}
 
		// Set bean properties from init parameters.
		try {
			//获得web.xml中的contextConfigLocation配置属性,就是spring MVC的配置文件
			PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
			BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
			ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
			bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
			//模板方法,可以在子类中调用,做一些初始化工作,bw代表DispatcherServelt
			initBeanWrapper(bw);
			//将配置的初始化值设置到DispatcherServlet中
			bw.setPropertyValues(pvs, true);
		}
		catch (BeansException ex) {
			logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
			throw ex;
		}
 
		// Let subclasses do whatever initialization they like.
		//模板方法,子类初始化的入口方法
		initServletBean();
 
		if (logger.isDebugEnabled()) {
			logger.debug("Servlet '" + getServletName() + "' configured successfully");
		}
	}

           

FrameworkServlet

public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware
           

FrameworkServlet继承了HttpServletBean,同时实现了ApplicationContextAware接口,利用ApplicationContextAware接口的setApplicationContext方法,可以拿到bean容器,ApplicationContext,这个时候FrameworkServlet就有了可以获取容器里所有Bean的能力了。

@Override
	public void setApplicationContext(ApplicationContext applicationContext) {
		if (this.webApplicationContext == null && applicationContext instanceof WebApplicationContext) {
			this.webApplicationContext = (WebApplicationContext) applicationContext;
			this.webApplicationContextInjected = true;
		}
	}
           

同时FrameworkServlet实现了HttpServlet 的 doGet、doPost等一系列方法,将这些请求移交到processRequest这个方法中处理。

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

		processRequest(request, response);
	}
           

下面看下processRequest做了哪些事

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

        long startTime = System.currentTimeMillis();
        Throwable failureCause = null;
        //获取LocaleContextHolder中存储的原先的LocaleContext【存储Locale信息】
        LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
        //获取当前请求中的LocaleContext
        LocaleContext localeContext = buildLocaleContext(request);
        //获取RequestContextHolder中存储的原先的RequestAttributes【RequestAttributes是Spring的一个接口,通过该接口可以get/set/removeAttribute】
        RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
        //获取当前请求中的ServletRequestAttributes
        ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);
        //使用request获取异步处理管理器
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
        //为异步处理管理器注册拦截器
        asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());
        //initContextHolders将当前请求的LocaleContext、ServletRequestAttributes设置到LocaleContextHolder、RequestContextHolder【initContextHolders的代码在本代码块后部分】
        initContextHolders(request, localeContext, requestAttributes);
        try {
            //实际处理的方法,在FrameworkServlet只是一个抽象方法由DispatcherServlet来实现【也是DispatcherServlet处理请求的入口】
            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恢复到LocaleContextHolder、RequestContextHolder
            resetContextHolders(request, previousLocaleContext, previousAttributes);
            if (requestAttributes != null) {
                //标记requestActive为false,代表当前请求已完成
                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");
                    }
                }
            }
            //发布ServletRequestHandledEvent消息
            publishRequestHandledEvent(request, response, startTime, failureCause);
        }
    }
           

这个方法主要做了

  • 异步请求的处理
  • 调用doService方法具体处理请求
  • 处理LocaleContext和RequestAttributes

这个doService是一个钩子,会直接调用DispatcherServlet的doService方法。

这里就可以得到请求处理过程的全貌了:

HttpServlet service(ServletRequest req, ServletResponse res)

→FrameworkServlet service(HttpServletRequest request, HttpServletResponse response)

→HttpServlet service(HttpServletRequest req, HttpServletResponse resp)

→FrameworkServlet doGet/doXxxx

→FrameworkServlet processRequest

→DispatcherServlet doService

DispatcherServlet

针对DispatcherServlet,我们看下它的doService方法做了什么。

//获取请求,设置一些request的参数,然后分发给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.
		Map<String, Object> attributesSnapshot = null;
		if (WebUtils.isIncludeRequest(request)) {
			attributesSnapshot = new HashMap<String, Object>();
			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.
		/* 设置web应用上下文**/
		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));
		}
		//Flash attributes 在对请求的重定向生效之前被临时存储(通常是在session)中,并且在重定向之后被立即移除
		request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
		//FlashMap 被用来管理 flash attributes 而 FlashMapManager 则被用来存储,获取和管理 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);
				}
			}
		}
	}
           

doService设置了一些属性,然后交予doDispatch方法继续处理,DispatcherServlet的doDispatch方法主要用作职责调度工作,本身主要用于控制流程,也是我们比较关注的一个点,即DispatcherServlet如何协调组件进行处理http请求,源码如下:

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 {
				//1、文件上传解析,如果请求类型是multipart将通过MultipartResolver进行文件上传解析;
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);
 
				//2.通过HandlerMapping,将请求映射到处理器(返回一个HandlerExecutionChain,它包括一个处理器、多个HandlerInterceptor拦截器);
				// Determine handler for the current request.
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null || mappedHandler.getHandler() == null) {
					noHandlerFound(processedRequest, response);
					return;
				}
				//3、通过HandlerAdapter支持多种类型的处理器(HandlerExecutionChain中的处理器);
				// 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();//得到当前的http方法。
				boolean isGet = "GET".equals(method);
				if (isGet || "HEAD".equals(method)) {//处理http的head方法。这种方法应该很少用
					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;
					}
				}
				//4.1调用HandlerExecutionChain的interceptor
				if (!mappedHandler.applyPreHandle(processedRequest, response)) {
					return;
				}
				
				//4.2执行解析handler中的args,调用(invoke) controller的方法。得到视图
				// Actually invoke the handler.
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
 
				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}
				//4.3调用HandlerExecutionChain的interceptor
				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);
			}
			//5.解析视图、处理异常
			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);
				}
			}
		}
	}

           

这样请求就处理完成了,具体各个组件是如何进行工作的,后面找时机专门看下。