SpringMVC源码阅读(一)

275 阅读8分钟

前言

本篇文章我们将一起阅读springMVC的源码内容。在springMVC中有涉及到策略模式和适配器模式这两种这设计模式,但是我们的重点是在源码阅读上,因此对着两种模式只是稍微提及并不会做过多的深入讲解,大家可以先去了解下这两种模式之后再来阅读下面的内容,可以提高对这两种模式的理解。
阅读源码之前我们先来看一张大家应该很熟悉的图-springMVC的架构图

从这张图中我们可以很清晰的看到springMVC的一个工作流程。因为现在的开发方式基本上都是前后端分离,数据主要以json形式传输,因为对于springMVC的视图这块我们就忽略了。所以,本次源码阅读主要阅读springMVC的以下六个流程,本篇文章主要阅读前两个流程。

  • DispatcherServlet的初始化流程
  • DispatcherServlet处理请求的流程
  • 处理器映射器RequestMappingHandlerMapping的初始化流程
  • 处理器映射器RequestMappingHandlerMapping查找对应的处理器的流程
  • 处理器适配器RequestMappingHandlerAdapter初始化流程
  • 处理器适配器RequestMappingHandlerAdapter的执行流程

DispatcherServlet的初始化流程

开始阅读DispatcherServlet的初始化流程之前,我们首先得知道Servlet的生命周期

servlet的生命周期方法

  • init: Servlet 对象创建之后调用
  • service: Servlet 对象被 HTTP 请求访问时调用
  • destroy: Servlet 对象销毁之前调用 因此,我们要了解初始化流程就应该从init方法入手,接下去我们看下DispatcherServlet的继承体系

DispatcherServlet的继承体系

从这个继承体系中我们可以看出,DispatcherServlet主要有两个继承体系,一,是继续Servlet,二,是springIOC相关的继承体系。

DispatcherServlet的初始化流程入口

因此初始化流程的入口,我们就找Servlet继承体系中哪个类实现了init方法。最终可以找到, HttpServletBean这个类实现了init方法

@Override
	public final void init() throws ServletException {
		。。。。。忽略

		// Let subclasses do whatever initialization they like.
		initServletBean();

		if (logger.isDebugEnabled()) {
			logger.debug("Servlet '" + getServletName() + "' configured successfully");
		}
	}

这里面其实最主要的就是initServletBean,初始化Servlet对象,就是初始化DispatcherServlet,我们接着看子类FrameworkServlet重写了该方法

	protected final void initServletBean() throws ServletException {
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		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();
		}
		if (wac == null) {
			// No context instance is defined for this servlet -> create a local one
			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.
			
			// 刷新策略
			onRefresh(wac);
		}

	。。。

		return wac;
	}

这段代码中我们可以看到configureAndRefreshWebApplicationContext这个方法就是去完成容器的初始化,看下这个具体的内容

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
		。。。

		postProcessWebApplicationContext(wac);
		applyInitializers(wac);
		// 调用容器初始化方法
		wac.refresh();
	}

前面的内容都不用看,看到这个refresh方法我想大家就都懂了,这个方法就是去初始化spring容器的方法。 到这里我们就知道了,springMVC在初始化的时候去启动了spring容器,而在initServletBean中还有一个很重要的方法,在上面的代码中也加了注释就是onRefresh方法,这个方法主要是初始化了DispatcherServlet类中的各种策略,具体是由DispatcherServlet自己实现的,我们看下具体的内容,点进去可以进入到具体的initStrategies方法

protected void initStrategies(ApplicationContext context) {
		// 初始化多部件解析器
		initMultipartResolver(context);
		// 初始化国际化解析器
		initLocaleResolver(context);
		// 初始化主题解析器
		initThemeResolver(context);
		// 初始化处理器映射器
		initHandlerMappings(context);
		// 初始化处理器适配器
		initHandlerAdapters(context);
		// 初始化异常解析器
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		// 初始会视图解析器
		initViewResolvers(context);
		initFlashMapManager(context);
	}

这里面就初始化了各种策略,我们主要看一个就好了,剩下的大家有兴趣可以自己一个个去阅读,我们主要看下初始化处理器映射器策略,也就是进入initHandlerMappings方法

private void initHandlerMappings(ApplicationContext context) {
		this.handlerMappings = null;

		if (this.detectAllHandlerMappings) {
			// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
			// 从当前spring容器中,查找到所有的处理器映射器
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<>(matchingBeans.values());
				// We keep HandlerMappings in sorted order.
				AnnotationAwareOrderComparator.sort(this.handlerMappings);
			}
		}
		else {
			try {
				HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
				this.handlerMappings = Collections.singletonList(hm);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerMapping later.
			}
		}

		// Ensure we have at least one HandlerMapping, by registering
		// a default HandlerMapping if no other mappings are found.
		if (this.handlerMappings == null) {
			// 如果没有从spring容器中获取到HandlerMapping,那么会从DispatcherServlet.properties文件中加载默认策略
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
			}
		}
	}

这段代码就是从spring容器中加载处理器映射器,如果没有就会从默认的配置文件中加载。而detectAllHandlerMappings参数的默认为true,true的话表示获取容器中所有的处理器映射器,而如果配置成fasle就会指定加载一个类名叫handlerMapping的处理器映射器。 至此,DispatcherServlet的初始化流程我们就阅读完毕了,接下去我们去看下DispatcherServlet处理请求的过程

DispatcherServlet处理请求的过程

我们指定在Servlet中处理请求是由由service方法进行处理的,因此我们找到service方法的实现类,就是HttpServlet的service方法

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);
        }

这里就是通过不同的请求方式去处理不同的请求,我们主要找doGet和doPost的实现方法,我们可以找到FrameworkServlet实现了这两个方法

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

		processRequest(request, response);
	}

	/**
	 * Delegate POST requests to {@link #processRequest}.
	 * @see #doService
	 */
	@Override
	protected final void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		processRequest(request, response);
	}

继续往下processRequest方法里面有一行重要的代码

try {
		doService(request, response);
	}

这个方法是个抽象方法,而他的实现类就是DispatcherServlet,到这里我们就知道请求最终会调用到DispatcherServlet的doService方法中,这个方法里面我们主要关注的就是doDispatch方法,就是分发请求,我们直接看DispatcherServlet的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.
				// 获取handler处理器的执行链,执行链封装了处理器和对应该处理器的拦截器
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// Determine handler adapter for the current request.
				// 通过找到的Handler处理器,去匹配合适的处理器适配器HandlerAdapter
				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(processedRequest, mv);
				// 执行拦截器(interceptor)的postHandle方法
				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) {
			// 执行拦截器(interceptor)的afterCompletion方法
			triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
		}
		catch (Throwable err) {
			// 执行拦截器(interceptor)的afterCompletion方法
			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);
				}
			}
		}
	}

这个方法里面就是处理请求的过程

  • 判断是否是文件上传,是的话就调用相应的方法处理
  • 通过处理器映射器获取处理器形成执行链
  • 通过处理器找到对应的处理器适配器
  • 执行拦截器(preHandler方法)-前置拦截器
  • 通过处理器适配器调用真正的处理方法(就是我们@Controller里面的具体方法)
  • 执行拦截器(postHandler方法)-后置拦截器
  • 进行视图解析渲染 到这里,DispatcherServlet处理请求的流程我们就已经阅读完毕了。

最后

到这里我们对DispatcherServlet的初始化及请求处理流程已经阅读完毕,下一篇文章我们会带着大家继续阅读剩下的四个流程主要是处理器映射器和处理器适配器的初始化和执行流程。