SpringMvc源码解析(基于5.0.9)

spring源码

研究源码前,先找到入库类,再根据入口方法一步一步跟踪深入。SpringMvc的入口类为配置在web.xml中继承了servlet的DispatcherServlet,以下是他的继承关系:
SpringMvc源码解析(基于5.0.9)_第1张图片

初始化

1、HttpServletBean中对servlet的初始化

先看这个特殊的servlet的init方法,封装在了HttpServletBean:

public final void init() throws ServletException {
		if (logger.isDebugEnabled()) {
			logger.debug("Initializing servlet '" + getServletName() + "'");
		}

		// 获取配置在web.xml中的自定义参数,并封装到内部类ServletConfigPropertyValues中
		// Set bean properties from init parameters.
		PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
		//在spring boot项目中由于没有配置初始化参数,所以不会执行里面的代码
		if (!pvs.isEmpty()) {
			try {
				BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
				ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
				bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
				//空方法,供子类重写,遗憾的是没有发现在任何子类重写了他
				initBeanWrapper(bw);
				bw.setPropertyValues(pvs, true);
			}
			catch (BeansException ex) {
				if (logger.isErrorEnabled()) {
					logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex);
				}
				throw ex;
			}
		}

		//该类中是个空方法,但是在FrameworkServlet该方法已经被重写,用于做一些容器话的操作,比如设置webApplication,设置父容器等
		// Let subclasses do whatever initialization they like.
		initServletBean();

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

2、 FrameworkServlet中将servelet与IoC容器的融合

来看下FrameworkServlet重写的initServletBean()做了什么:

protected final void initServletBean() throws ServletException {
		getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'");
		if (this.logger.isInfoEnabled()) {
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
			//初始化webApplicationContext容器
			this.webApplicationContext = initWebApplicationContext();
			//又是一个空方法,没有做任何实现
			initFrameworkServlet();
		}
		catch (ServletException | RuntimeException ex) {
			this.logger.error("Context initialization failed", ex);
			throw ex;
		}

		if (this.logger.isInfoEnabled()) {
			long elapsedTime = System.currentTimeMillis() - startTime;
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
					elapsedTime + " ms");
		}
	}

该代码主要用来初始化webApplicationContext容器,webApplicationContext是一个继承于ApplicationContext的ioc上下文容器。类FrameworkServlet主要作用就是把Spring与servler相关联。

真正创建WebApplicationCont容器的方法:

protected WebApplicationContext initWebApplicationContext() {
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		// 使用DispatcherServlet的有个带参的WebApplicationContext 的构造方法,当使用该构造方式实例化的时候,会执行该代码
		if (this.webApplicationContext != null) {
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				if (!cwac.isActive()) {
					//没被初始化过的话(没调用过refreshed方法),设置父容器
					if (cwac.getParent() == null) {
						cwac.setParent(rootContext);
					}
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		if (wac == null) {
		//以setContextAttribute的方式将ServletContext设置进来
			wac = findWebApplicationContext();
		}
		if (wac == null) {
		//反射方式创建一个默认的,XmlWebApplicationContext类型
		//设置环境environment,父容器,本地资源文件
			wac = createWebApplicationContext(rootContext);
		}

		if (!this.refreshEventReceived) {
			//调用ioc容器的onRefresh方法,准备做ioc容器的初始化动作
			//该方法是个空方法,在DispatcherServlet中被重写
			//最后执行容器的refresh方法
			onRefresh(wac);
		}

		//将容器设置到servletContext上下文中
		if (this.publishContext) {
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
			if (this.logger.isDebugEnabled()) {
				this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
						"' as ServletContext attribute with name [" + attrName + "]");
			}
		}

		return wac;
	}

3、DispatcherServlet中的初始化各组件的入口函数

WebApplicationContext被创建后(同时关联上父容器),接下来调用IOC容器的onRefresh方法,该方法在FrameworkServlet是个空方法,但是在DispatcherServlet中重写了,onRefresh才是真正初始化SpringMvc的入口方法:

	@Override
	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}

	protected void initStrategies(ApplicationContext context) {
		//解析请求
		initMultipartResolver(context);
		//多语言环境,国际化
		initLocaleResolver(context);
		//主题
		initThemeResolver(context);
		//解析url和methdo的关系,存于requestMap实体类中
		initHandlerMappings(context);
		//适配器的匹配
		initHandlerAdapters(context);
		//异常处理器
		initHandlerExceptionResolvers(context);
		//视图转发
		initRequestToViewNameTranslator(context);
		//解析模板中的类容,生成html代码
		initViewResolvers(context);
		//映射管理器
		initFlashMapManager(context);
	}

onRefresh方法直接调用了initStrategies方法,里面做了一些初始化操作。下面将讲解在DispatcherServlet中一些重要组件的初始化。

4、三个核心类的作用

  1. HttpServletBean
      主要做一些Servlet的初始化的工作,将web.xml中配置的参数设置到Servlet中。比如servlet标签的子标签init-param标签中配置的参数。提供了initServletBean模板方法供FrameworkServlet实现,从而引出后续操作。
  2. FrameworkServlet
      将Servlet与Spring IoC容器关联。作用就是初始化FrameworkServlet的属性webApplicationContext,这个属性代表SpringMVC上下文,它有个父类上下文,既web.xml中配置的ContextLoaderListener监听器初始化的容器上下文。提供onRefresh模板方法供DispatcherServlet实现,为其初始化SpringMvc组件提供入口。
  3. DispatcherServlet
      初始化各个组件的实现类。比如异常处理、视图处理、请求映射处理等。处理用户的请求。

##5、HandlerMapping初始化

private void initHandlerMappings(ApplicationContext context) {
		//一个list集合
		this.handlerMappings = null;

		if (this.detectAllHandlerMappings) {
			// 获取所有注册到容器中的handlerMapping
			Map<String, HandlerMapping> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerMappings = new ArrayList<>(matchingBeans.values());
				//排序
				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.
			}
		}

		// 如果没从容器中获取到的化,默认俩个默认的handlerMappering
		if (this.handlerMappings == null) {
			this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
			}
		}
	}

在初始化HandlerMapping的时候,如果发现用户没有设置任何handlerMapping,则会读取本地org.springframework.web.servlet.DispatcherServlet.properties文件中的配置项:

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping

创建俩个默认:

BeanNameUrlHandlerMapping
RequestMappingHandlerMapping

6、HandlerAdapter初始化

private void initHandlerAdapters(ApplicationContext context) {
		//同样,也是list集合
		this.handlerAdapters = null;

		if (this.detectAllHandlerAdapters) {
			// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
			Map<String, HandlerAdapter> matchingBeans =
					BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
			if (!matchingBeans.isEmpty()) {
				this.handlerAdapters = new ArrayList<>(matchingBeans.values());
				// 也需要排个序
				AnnotationAwareOrderComparator.sort(this.handlerAdapters);
			}
		}
		else {
			try {
				HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
				this.handlerAdapters = Collections.singletonList(ha);
			}
			catch (NoSuchBeanDefinitionException ex) {
				// Ignore, we'll add a default HandlerAdapter later.
			}
		}

		// Ensure we have at least some HandlerAdapters, by registering
		// default HandlerAdapters if no other adapters are found.
		if (this.handlerAdapters == null) {
			this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
			if (logger.isDebugEnabled()) {
				logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
			}
		}
	}

请求流程

用户请求服务器时,进入DispatcherServlet的doService方法,该方法最终调用了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);

				// 关键代码,找到该请求对应的handler
				mappedHandler = getHandler(processedRequest);
				//找不到对应的handler,报404
				if (mappedHandler == null) {
					noHandlerFound(processedRequest, response);
					return;
				}

				// 找到对应的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;
				}

				// 获取请求结果,封装到modelAndView中了
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

				if (asyncManager.isConcurrentHandlingStarted()) {
					return;
				}

				applyDefaultViewName(processedRequest, mv);
				mappedHandler.applyPostHandle(processedRequest, response, mv);
			}
			catch (Exception ex) {
				dispatchException = ex;
			}
			catch (Throwable err) {
				// 
				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()) {
				// 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);
				}
			}
		}
	}

接下来是getHander方法找到请求对应的handler:


@Nullable
protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {

	//从initHandlerMappings初始化产生的list中寻找合适的hanlder
	if (this.handlerMappings != null) {
		for (HandlerMapping hm : this.handlerMappings) {

			//匹配handler,最终跳转到了AbstractHandlerMapping的getHandler
			HandlerExecutionChain handler = hm.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
	}
	return null;
}

继续getHandlerAdapter方法

	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		if (this.handlerAdapters != null) {
			for (HandlerAdapter ha : this.handlerAdapters) {
			
				//查看该handleradapter是否支持该handler
				if (ha.supports(handler)) {
					return ha;
				}
			}
		}
		throw new ServletException("No adapter for handler [" + handler +
				"]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
	}

上面代码中ha.supports(handler),该方法是判断该adapter是否适配handler,这就是springMvc里面经典的适配器模式了。不同的handlerAdapter方法适配规则不一样。但是都很简单,以HttpRequestHandlerAdapter为例:

	public boolean supports(Object handler) {
		return (handler instanceof HttpRequestHandler);
	}

你可能感兴趣的:(SpringMvc源码解析(基于5.0.9))