从spring容器启动解析webmvc源码

3 篇文章 0 订阅
1 篇文章 0 订阅

Spring webmvc启动流程

本文将从spring容器启动过程去分析springmvc源码,首先我们思考一个问题:

web容器在启动的时候是怎么将bean解析并加载到spring容器中的,像我们自己如果要启动容器,那是不是要new ApplicationContext(),并且把xml配置文件路径或者包扫描路径传进去。那么webmvc是怎么解决这个问题的呢?

以tomcat为例,我们的web应用程序是部署在tomcat的容器中的,那么tomcat就为我们的应用提供了一个全局的上下文环境,也就是ServletContext,spring的applicationContext最终也是注入到ServletContext当中的。我们在springmvc的开发过程中,在web.xml中经常会有如下配置:

  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:application.xml</param-value>
  </context-param>
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

web容器在启动的时候会加载三个组件:listener >> filter >> servlet

而我们在web.xml中配置的一个很重要的listener就是ContextLoaderListener,这个监听器实现了ServletContextListener,ServletContextListener它能够监听ServletContext对象的生命周期,也就是web应用的生命周期。在web容器启动或者终止时会触发ServletContextEvent事件,ServletContextListener监听的就是这个事件,分别调用contextInitialized和contextDestroyed

也就是说容器启动的时候会调用ContextLoaderListener的contextInitialized方法,ContextLoaderListener同时还继承了ContextLoader

	// 初始化web容器上下文
	public void contextInitialized(ServletContextEvent event) {
		initWebApplicationContext(event.getServletContext());
	}

转到父类ContextLoader中的initWebApplicationContext,spring容器的初始化入口

// ContextLoader:

	public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		// 这些都忽略,往下看重点
		if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
			throw new IllegalStateException(
					"Cannot initialize context because there is already a root application context present - " +
					"check whether you have multiple ContextLoader* definitions in your web.xml!");
		}

		Log logger = LogFactory.getLog(ContextLoader.class);
		servletContext.log("Initializing Spring root WebApplicationContext");
		if (logger.isInfoEnabled()) {
			logger.info("Root WebApplicationContext: initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
			// Store context in local instance variable, to guarantee that
			// it is available on ServletContext shutdown.
			if (this.context == null) {
				// 这里就是重点了,创建applicationContext,默认为xmlWebApplicationContext
				this.context = createWebApplicationContext(servletContext);
			}
			if (this.context instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
				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 ->
						// determine parent for root web application context, if any.
						ApplicationContext parent = loadParentContext(servletContext);
						cwac.setParent(parent);
					}
					// 重点,就是在这一步加载的spring 配置,
					configureAndRefreshWebApplicationContext(cwac, servletContext);
				}
			}
// 在这里将applicationContext注入到servletContext当中	servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);

			ClassLoader ccl = Thread.currentThread().getContextClassLoader();
			if (ccl == ContextLoader.class.getClassLoader()) {
				currentContext = this.context;
			}
			else if (ccl != null) {
				currentContextPerThread.put(ccl, this.context);
			}

			if (logger.isDebugEnabled()) {
				logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
						WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
			}
			if (logger.isInfoEnabled()) {
				long elapsedTime = System.currentTimeMillis() - startTime;
				logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
			}

			return this.context;
		}
		catch (RuntimeException ex) {
			logger.error("Context initialization failed", ex);
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
			throw ex;
		}
		catch (Error err) {
			logger.error("Context initialization failed", err);
			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
			throw err;
		}
	}

我们看一下创建spring容器的过程:createWebApplicationContext(servletContext)

// ContextLoader:

protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
        // 很明显这里决定了spring容器的类型
		Class<?> contextClass = determineContextClass(sc);
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
					"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
		}
		return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

往下看determineContextClass的源码:

// ContextLoader:390

protected Class<?> determineContextClass(ServletContext servletContext) {
		// 默认的contextClass的名称
		String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
		if (contextClassName != null) {
			try {
				return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load custom context class [" + contextClassName + "]", ex);
			}
		}
		else {
			// 从properties中获取类名,接着看这个defaultStrategies是什么时候赋值的
			contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
			try {
				return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
			}
			catch (ClassNotFoundException ex) {
				throw new ApplicationContextException(
						"Failed to load default context class [" + contextClassName + "]", ex);
			}
		}
	}

	static {
		// Load default strategy implementations from properties file.
		// This is currently strictly internal and not meant to be customized
		// by application developers.
		try {
			// 从DEFAULT_STRATEGIES_PATH获取到资源
			ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
			// 就是在这里对 defaultStrategies进行的初始化
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
		}
	}

我们可以看到是从DEFAULT_STRATEGIES_PATH这个路径获取到的类名配置

	private static final String DEFAULT_STRATEGIES_PATH = "ContextLoader.properties";

这个ContextLoader.properties其实就是在spring-web中org.springframework.web.context.ContextLoader的同级目录下:

可以看到webmvc默认创建容器的实现类就是XmlWebApplicationContext,最后通过反射获取实例

至此spring容器已创建,下面bean的初始化configureAndRefreshWebApplicationContext

// ContextLoader:413

	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
		if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
			// The application context id is still set to its original default value
			// -> assign a more useful id based on available information
			String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
			if (idParam != null) {
				wac.setId(idParam);
			}
			else {
				// Generate default id...
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(sc.getContextPath()));
			}
		}

		wac.setServletContext(sc);
		// 这一步得到了web.xml中设置的<param-name>:contextConfigLocation,即spring配置文件路径
		String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
		if (configLocationParam != null) {
			// contextConfigLocation赋值
			wac.setConfigLocation(configLocationParam);
		}

		// The wac environment's #initPropertySources will be called in any case when the context
		// is refreshed; do it eagerly here to ensure servlet property sources are in place for
		// use in any post-processing or initialization that occurs below prior to #refresh
		// 初始化spirng环境
		ConfigurableEnvironment env = wac.getEnvironment();
		if (env instanceof ConfigurableWebEnvironment) {
			((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
		}

		customizeContext(sc, wac);
		// 重点,spring的bean加载,实例化等相关操作都在这里了
		wac.refresh();
	}

在这里把web.xml中配置的contextConfigLocation参数传给了applicationContext。最后是spring真正初始化的地方:wac.refresh();

// AbstractApplicationContext:509

	public void refresh() throws BeansException, IllegalStateException {
		synchronized (this.startupShutdownMonitor) {
			// Prepare this context for refreshing.
			prepareRefresh();

			// Tell the subclass to refresh the internal bean factory.
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// Prepare the bean factory for use in this context.
			prepareBeanFactory(beanFactory);

			try {
				// Allows post-processing of the bean factory in context subclasses.
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				initMessageSource();

				// Initialize event multicaster for this context.
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				onRefresh();

				// Check for listener beans and register them.
				registerListeners();

				// Instantiate all remaining (non-lazy-init) singletons.
				finishBeanFactoryInitialization(beanFactory);

				// Last step: publish corresponding event.
				finishRefresh();
			}

			catch (BeansException ex) {
				if (logger.isWarnEnabled()) {
					logger.warn("Exception encountered during context initialization - " +
							"cancelling refresh attempt: " + ex);
				}

				// Destroy already created singletons to avoid dangling resources.
				destroyBeans();

				// Reset 'active' flag.
				cancelRefresh(ex);

				// Propagate exception to caller.
				throw ex;
			}

			finally {
				// Reset common introspection caches in Spring's core, since we
				// might not ever need metadata for singleton beans anymore...
				resetCommonCaches();
			}
		}
	}

这里涉及spring初始化过程的代码比较复杂,就不在此文中叙述了。下面开始探讨DispatcherServlet

DispatcherServlet

在开始分析DispatcherServlet之前,我们看一下springmvc的整个流程

接着分析DispatcherServlet

  <servlet>
    <servlet-name>dispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>dispatcherServlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>

在web.xml中配置的DispatcherServlet是springmvc的核心组件,接收到的请求都交由DispatcherServlet来处理。web容器在加载完listener后filter之后,会根据load-on-startup指定的级别开始初始化servlet,并调用其init()方法

从上面的类图我们可以看到,DispatcherServlet实现了Servlet接口,Servlet中提供了初始化方法:init(),其具体实现在DispatcherServlet继承的HttpServletBean中

// servlet >> HttpServletBean

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

		// 获取servlet初始化配置参数
		PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
		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;
			}
		}

		// 重点是这里,初始化servlet实例
		initServletBean();

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

继续看初始化servlet的过程:initServletBean,其具体实现在FrameworkServlet中

// FrameworkServlet

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

这里又看到了initWebApplicationContext,是不是很眼熟,我们进入到initWebApplicationContext中

// FrameworkServlet:522

	protected WebApplicationContext initWebApplicationContext() {
		// 由于我们配置了ContextLoaderListener,前面创建xmlWebApplicationContext的时候已经给
		// rootContext注入了值,这里就是从servletContext当中获取之前的根上下文
		// 如果没有配置ContextLoaderListener,那么此处的rootContext为null,不过不影响springmvc,我们接着往下看
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;
		// dispatcher在初始化的时候会建立自己的IOC上下文,
		// 用来存储springmvc相关的bean,在创建之前,
		// 要判断一下servlet的上下文中是否已经存在webApplicationContext

		// 这个时候dispatcher的webApplicationContext还是null,所以默认情况不会走这个分支
		if (this.webApplicationContext != null) {
			// 如果存在那就直接拿来用
			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
						// 将之前的根上下文作为自己的parent
						cwac.setParent(rootContext);
					}
					// 初始化applicationContext
					configureAndRefreshWebApplicationContext(cwac);
				}
			}
		}
		// 因为wac还是null,所以会进入到这个分支
		if (wac == null) {
			// No context instance was injected at construction time -> see if one
			// has been registered in the servlet context.
			// 去servlet的上下文中找是否已经存在webApplicationContext
			wac = findWebApplicationContext();
		}
		// 上述都找不到,所以会进到这里
		if (wac == null) {
			// 重点,创建自己的WebApplicationContext
			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.
			// refreshed -> trigger initial onRefresh manually here.
			onRefresh(wac);
		}
		// 将dispatcher创建的WebApplicationContext注入到servletContext中
		if (this.publishContext) {
			// Publish the context as a servlet context attribute.
			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;
	}

我们再转到createWebApplicationContext,前面分析listener创建springioc容器时候,也有调用类似方法

// FrameworkServlet:614

	protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) {
		// 获取class对象,这里也是XmlWebApplicationContext
		Class<?> contextClass = getContextClass();
		if (this.logger.isDebugEnabled()) {
			this.logger.debug("Servlet with name '" + getServletName() +
					"' will try to create custom WebApplicationContext context of class '" +
					contextClass.getName() + "'" + ", using parent context [" + parent + "]");
		}
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException(
					"Fatal initialization error in servlet with name '" + getServletName() +
					"': custom WebApplicationContext class [" + contextClass.getName() +
					"] is not of type ConfigurableWebApplicationContext");
		}
		// 通过反射实例化XmlWebApplicationContext
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
		// 设置spring环境
		wac.setEnvironment(getEnvironment());
		// 将从servletContext中获取的跟上下文作为自己的parent
		wac.setParent(parent);
		// 设置我们在web.xml中dispatcherServlet节点下配置的<param-name>contextConfigLocation,本文中配置的是mvc.xml
		wac.setConfigLocation(getContextConfigLocation());
		// 这里最终还是调用refresh,进行springmvc相关bean加载和初始化等工作,前面已经说过了,这里不再说
		configureAndRefreshWebApplicationContext(wac);

		return wac;
	}

这里最终是调用configureAndRefreshWebApplicationContext,又到了这个熟悉的方法,继续跟进

// FrameworkServlet:639

	protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {
		.......

		postProcessWebApplicationContext(wac);
		applyInitializers(wac);
		// 在这里初始化
		wac.refresh();
	}
	// 接口
	void refresh() throws BeansException, IllegalStateException;

接着追踪wac.refresh()的具体实现
// AbstractApplicationContext:509

	public void refresh() throws BeansException, IllegalStateException {
		// 先来个锁,不然容器还没refresh,你又启动个容器,那不得炸了,要知道是可以启动多个容器的
		synchronized (this.startupShutdownMonitor) {
			// 记录下容器启动时间,标记为“已启动”
			prepareRefresh();

			// 这一步针对不同方式注入采取不同实现
			// 如果是xml方式,是在这一步初始化beanfactory,解析xml配置文件得到bean定义,
			// 扫描@component,@service,@repository,完成bean注册
			// 如果为annotation方式,在执行refresh之前就已经完成了BeanFactory的初始化
			// 和Bean容器注册,此时里面的逻辑是非常简单的,我们进去看看
			ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

			// 设置beanfactory的类加载器
			prepareBeanFactory(beanFactory);

			try {
				// Bean如果实现了BeanFactoryPostProcessor,容器在初始化以后会调用postProcessBeanFactory方法,并且子类可以对这步进行扩展
				postProcessBeanFactory(beanFactory);
    
				// 调用BeanFactoryPostProcessor实现类的postProcessBeanFactory回调
				invokeBeanFactoryPostProcessors(beanFactory);

				// 注册BeanPostProcessor实现类
				registerBeanPostProcessors(beanFactory);

				// 初始化MessageSource,国际化
				initMessageSource();

				// 初始化事件广播器
				initApplicationEventMulticaster();

				// 模版方法,子类可以在这一步初始化一些bean
				onRefresh();

				// 注册监听器(实现ApplicationListener)
				registerListeners();

				// 实例化所有非懒加载的singleton benas
				finishBeanFactoryInitialization(beanFactory);

				// 初始化完成广播事件
				finishRefresh();
			}

			......
		}
	}

这里又到了spring的最核心的方法:refresh(),这个方法里有一个比较重要的步骤: obtainFreshBeanFactory(),我们在mvc相关的配置文件中配置的<context:component-scan>,就是一步通过解析xml拿到扫描路径的。经过一系列的调用链路,会调用doScan,传入包扫描路径,将@component,@service,@repository这些注解标识的类注册到spring ioc容器。

<context:component-scan base-package="com.cf.spring.code"></context:component-scan>

spring完成bean注册后,会在finishBeanFactoryInitialization这一步统一完成bean的实例化。spring容器的bean初始化完成后最还有一个广播事件:finishRefresh():
经过一系列的调用链路
AbstractApplicationContext.finishRefresh()
>> AbstractApplicationContext.publishEvent(new ContextRefreshedEvent(this)) //向所有监听者发布容器刷新事件>> FrameworkServlet.onApplicationEvent(ContextRefreshedEvent event) //接收到容器刷新事件,调用DispatcherServlet的onRefresh
>> DispatcherServlet.onRefresh()

最终会调用DispatcherServlet的onRefresh()方法,而onRefresh()里就一行代码,真正干实事的是initStrategies

// DispatcherServlet

	protected void onRefresh(ApplicationContext context) {
		initStrategies(context);
	}
    // springmvc组件一系列初始化操作
	protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		// 初始化handlerMapping
		initHandlerMappings(context);
		// 初始化HandlerAdapters
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		// 初始化视图解析器
		initViewResolvers(context);
		initFlashMapManager(context);
	}

DispatcherServlet的initStrategies完成了springmvc组件的一系列初始化操作,也就是说springmvc组件在DispatcherServlet初始化自己的上下文(webApplicationContext)的时候就已经实例化完成了。

至此我们已经知道springmvc是怎么加载bean并完成初始化的流程,接下来分析一波dispatcherServlet如何处理请求。

DispatcherServlet继承了HttpServlet,servlet处理请求最核心的方法就是service()方法,但是在DispatcherServlet的父类FrameworkServlet中重写了service方法:

// FrameworkServlet

	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
		// 判断是不是patch的请求方式
		if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
			processRequest(request, response);
		}
		// 如果不是patch的请求方式,调用父类的service方法,最终还是会调用本类中的doGet和doPost方法
		else {
			super.service(request, response);
		}
	}
	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

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

		processRequest(request, response);
	}

不管是doPost还是doGet,都 会调用processRequest(request, response)方法

// FrameworkServlet

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

		......

		try {
			// 这里才是重点,别的都略过,跟进去
			doService(request, response);
		}
		catch (ServletException ex) {
			failureCause = ex;
			throw ex;
		}
		......

			publishRequestHandledEvent(request, response, startTime, failureCause);
		}
	}

这里的doService是abstract的,其实现是在DipatcherServlet中

// DipatcherServlet

	protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
		......
		try {
            // 继续,跟进
			doDispatch(request, response);
		}
		......
	}

终于到了SpringMvc最核心的代码:doDispatch

// DipatcherServlet

	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;//定义ModelAndView
			Exception dispatchException = null;

			try {
				// 判断是否上传文件请求
				processedRequest = checkMultipart(request);
				multipartRequestParsed = (processedRequest != request);

				// 通过当前request对象获取handler,handler是什么?就是指处理器(像controller)
				// 下面重点分析一下handler获取的过程
				mappedHandler = getHandler(processedRequest);
				if (mappedHandler == null || mappedHandler.getHandler() == 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;
				}

				// 真正执行handle
				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) {
				// 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()) {
				// 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);
				}
			}
		}
	}

处理请求时首先会根据当前的request获取一个handler

	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		// 遍历handlerMappings
		for (HandlerMapping hm : this.handlerMappings) {
			if (logger.isTraceEnabled()) {
				logger.trace(
						"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
			}
			// 找到具体handler
			HandlerExecutionChain handler = hm.getHandler(request);
			if (handler != null) {
				return handler;
			}
		}
		return null;
	}

	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		// 真正获取handler
		Object handler = getHandlerInternal(request);
		if (handler == null) {
			handler = getDefaultHandler();
		}
		if (handler == null) {
			return null;
		}
		// Bean name or resolved handler?
		if (handler instanceof String) {
			String handlerName = (String) handler;
			handler = getApplicationContext().getBean(handlerName);
		}
		// 获取handler执行链
		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
		if (CorsUtils.isCorsRequest(request)) {
			CorsConfiguration globalConfig = this.corsConfigSource.getCorsConfiguration(request);
			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
			CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}
		return executionChain;
	}

spring会遍历handlerMappings,询问每一个HandlerMapping,有没有我要的控制器,最终返回了HandlerExecutionChain
接着追踪下getHandlerInternal,以AbstractUrlHandlerMapping为例,分析一下根据url获取handler

// AbstractUrlHandlerMapping

	protected Object getHandlerInternal(HttpServletRequest request) throws Exception {
		// url路径
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		// 寻找handler,就是这里了,我们接着往下看
		Object handler = lookupHandler(lookupPath, request);
		......
		return handler;
	}

	protected Object lookupHandler(String urlPath, HttpServletRequest request) throws Exception {
		// handlerMap这是一个LinkedHashMap<String, Object>,键值为url,value为controller实例
		// 这里通过url从map中 获取到真正执行业务的controller的实例(handler)
		Object handler = this.handlerMap.get(urlPath);
		if (handler != null) {
			// Bean name or resolved handler?
			if (handler instanceof String) {
				String handlerName = (String) handler;
				handler = getApplicationContext().getBean(handlerName);
			}
			validateHandler(handler, request);
			return buildPathExposingHandler(handler, urlPath, urlPath, null);
		}

			return buildPathExposingHandler(handler, urlPath, urlPath, null);
		......
	}

我们继续看下一个关键步骤getHandlerAdapter(mappedHandler.getHandler()

// DipatcherServlet

	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
				......
				// 获取适配器
				HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());

				......
	}

接着看获取适配器的步骤

	protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
		for (HandlerAdapter ha : this.handlerAdapters) {
			if (logger.isTraceEnabled()) {
				logger.trace("Testing handler adapter [" + ha + "]");
			}
			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");
	}

在这里根据handler匹配合适的适配器,接着往下看.applyPreHandle(processedRequest, response)

	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
				......

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

	boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = 0; i < interceptors.length; i++) {
				HandlerInterceptor interceptor = interceptors[i];
				if (!interceptor.preHandle(request, response, this.handler)) {
					triggerAfterCompletion(request, response, null);
					return false;
				}
				this.interceptorIndex = i;
			}
		}
		return true;
	}

在applyPreHandle这一步调用了一系列拦截器的preHandle方法,接下来就是去执行handle

				// 正在的执行handle
				mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

找到handle方法的具体实现

// AnnotationMethodHandlerAdapter 

	public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		// 获取controller的class对象
		Class<?> clazz = ClassUtils.getUserClass(handler);
		Boolean annotatedWithSessionAttributes = this.sessionAnnotatedClassesCache.get(clazz);
		if (annotatedWithSessionAttributes == null) {
			annotatedWithSessionAttributes = (AnnotationUtils.findAnnotation(clazz, SessionAttributes.class) != null);
			this.sessionAnnotatedClassesCache.put(clazz, annotatedWithSessionAttributes);
		}

		if (annotatedWithSessionAttributes) {
			checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true);
		}
		else {
			checkAndPrepare(request, response, true);
		}

		// Execute invokeHandlerMethod in synchronized block if required.
		if (this.synchronizeOnSession) {
			HttpSession session = request.getSession(false);
			if (session != null) {
				Object mutex = WebUtils.getSessionMutex(session);
				synchronized (mutex) {
					return invokeHandlerMethod(request, response, handler);
				}
			}
		}
		// 这里才是执行controller对应方法的地方,继续看
		return invokeHandlerMethod(request, response, handler);
	}

	protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {

		ServletHandlerMethodResolver methodResolver = getMethodResolver(handler);
		// 获取到要执行的方法对象
		Method handlerMethod = methodResolver.resolveHandlerMethod(request);
		ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver);
		ServletWebRequest webRequest = new ServletWebRequest(request, response);
		ExtendedModelMap implicitModel = new BindingAwareModelMap();
		// 通过反射执行url对应controller中的方法
		Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel);
		// 获取modelAndView
		ModelAndView mav =
				methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest);
		methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest);
		return mav;
	}

到这里已经执行完url对应controller方法中的业务逻辑,并且返回了modelAndView

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值