- 简介
这两个星期都在看spring mvc源码,看来看去还是还是很多细节没了解清楚,在这里把看明白的记录下,欢迎在评论中一起讨论。
一、铺垫
spring mvc是基于servlet的,在正式分析之前,我们来看一下servlet的知识。servlet的生命周期通过三个方法init、service、destory来构建的。
- init():
在Servlet的生命周期中,仅执行一次init()方法。它是在服务器装入Servlet时执行的,负责初始化Servlet对象。可以配置服务器,以在启动服务器或客户机首次访问Servlet时装入Servlet。无论有多少客户机访问Servlet,都不会重复执行init()。
- service():
它是Servlet的核心,负责响应客户的请求。每当一个客户请求一个HttpServlet对象,该对象的Service()方法就要调用,而且传递给这个方法一个“请求”(ServletRequest)对象和一个“响应”(ServletResponse)对象作为参数。在HttpServlet中已存在Service()方法。默认的服务功能是调用与HTTP请求的方法相应的do功能。
- destroy():
仅执行一次,在服务器端停止且卸载Servlet时执行该方法。当Servlet对象退出生命周期时,负责释放占用的资源。一个Servlet在运行service()方法时可能会产生其他的线程,因此需要确认在调用destroy()方法时,这些线程已经终止或完成。
二、spring mvc启动过程
spring mcv的入口是DispatcherServlet,顾名思义就是调度servlet是服务请求调度,它的继承结构如下:
在整合spring mvc时,web.xml有这样配置,相信用过的都知道
<servlet> <servlet-name>mvc-dispatcher</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:mvc-dispatcher.xml</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>mvc-dispatcher</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping>
那根据servlet的知识,在服务器启动,创建dispatcherServlet对象,会执行init方法,根据DispaterServlet的继承关系,找到init方法在HttpServletBean中,下面我们来看一下这个
方法
public final void init() throws ServletException { if (logger.isDebugEnabled()) { logger.debug("Initializing servlet ‘" + getServletName() + "‘"); } // Set bean properties from init parameters. try { /*PropertyValuesz是封装在web.xml配置servlet参数信息 * <init-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:mvc-dispatcher.xml</param-value> </init-param> */ 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())); initBeanWrapper(bw); //将配置的初始化值设置到DispatcherServlet bw.setPropertyValues(pvs, true); } catch (BeansException ex) { logger.error("Failed to set bean properties on servlet ‘" + getServletName() + "‘", ex); throw ex; } //初始化spring mvc容器方法webApplicationContext,由子类的FrameworkServlet来实现 initServletBean(); if (logger.isDebugEnabled()) { logger.debug("Servlet ‘" + getServletName() + "‘ configured successfully"); } }
接下来看FrameworkServlet的initServletBean(),主要调了initWebApplicationContext()方法
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 { //初始化spring mcv容器 this.webApplicationContext = initWebApplicationContext(); initFrameworkServlet(); } catch (ServletException ex) { this.logger.error("Context initialization failed", ex); throw ex; } catch (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"); } }
initWebApplicationContext方法
protected WebApplicationContext initWebApplicationContext() { /* 在spring启动过程中,ContextLoaderListener回监听到,实例化IoC容器,并将此容器实例注册到ServletContext中,现在把IOC容器取出来 */ WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; if (wac == null) { //把IOC容器传进去,创建spring mvc自己的容器 wac = createWebApplicationContext(rootContext); } return wac; if (this.publishContext) { String attrName = getServletContextAttributeName(); //把创建好的spring mcv自己的容器设置到ServletContext容器中 getServletContext().setAttribute(attrName, wac); } }
createWebApplicationContext方法
protected WebApplicationContext createWebApplicationContext(ApplicationContext parent) { /*根据web.xml中的配置决定使用何种WebApplicationContext。默认情况下使用XmlWebApplicationContext web.xml中相关的配置context-param的名称“contextClass” */ Class<?> contextClass = getContextClass(); //获得spring mvc自己容器 ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); wac.setEnvironment(getEnvironment()); //指定父容器为IOC容器 wac.setParent(parent); //指定spring mcv 核心配置文件的位置classpath:mvc-dispatcher.xml wac.setConfigLocation(getContextConfigLocation()); //spring mcv 容器继续初始化 configureAndRefreshWebApplicationContext(wac); return wac; }