本文将分析SpringMVC自身的建立过程。web
SpringMVC核心Servlet的继承结构如图spring
能够看到Servlet的继承机构中一共有5个类GenericServlet,HttpServlet在Java中,剩下的三个类HttpServlet,HttpServlet,HttpServlet是SpringMVC中的,中点介绍着三个类的建立过程。app
这三个类直接实现三个接口EnvironmentCapable,EnvironmentAware,ApplicationContextAware其中XXXAware在Spring里表示对XXX能够感知,也就是你想要Spring的一下东西,能够经过实现XXXAware接口告诉Spring,Spring看到后就会给你送过了,而接收的方式是经过实现接口的惟一方法setXXX。如FrameworkServlet实现了ApplicationContextAware接口,会自动调用以下方法:ide
@Override public void setApplicationContext(ApplicationContext applicationContext) { if (this.webApplicationContext == null && applicationContext instanceof WebApplicationContext) { this.webApplicationContext = (WebApplicationContext) applicationContext; this.webApplicationContextInjected = true; } }
EnvironmentCapable是指拥有Environment的能力,也就是能够提供Environment,实现这个接口就是告诉Spring它能够提供Environment,须要的时候就会调用getEnvironment工具
@Override public ConfigurableEnvironment getEnvironment() { if (this.environment == null) { this.environment = createEnvironment(); } return this.environment; }
protected ConfigurableEnvironment createEnvironment() { return new StandardServletEnvironment(); }
@Override public final void init() throws ServletException { if (logger.isTraceEnabled()) { logger.trace("Initializing servlet '" + getServletName() + "'"); } // 将servlet中配置的参数封装到pvs变量中,requiredProperties为必须参数 若是没有将报异常 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())); //模板方法,能够在子类调用,作一些初始化操做,bw表明DispatcherServlet initBeanWrapper(bw); //将配置的初始值设置到bw表明DispatcherServlet bw.setPropertyValues(pvs, true); } catch (BeansException ex) { if (logger.isErrorEnabled()) { logger.error("Failed to set bean properties on servlet '" + getServletName() + "'", ex); } throw ex; } } // 模板方法,子类初始化入口 initServletBean(); if (logger.isTraceEnabled()) { logger.trace("Servlet '" + getServletName() + "' configured successfully"); } }
首先将Servlet中的配置参数使用BeanWarpper设置到DispatcherServlet的相关属性,而后调用模板方法,子类经过这个方法初始化,BeanWarpper是Spring提供的一个用来操做JavaBean属性的工具,使用它能够直接修改一个对象的属性。post
从HttpServletBean中可知,FrameworkServlet的初始化入口方法应该是initServletBean其代码以下ui
@Override protected final void initServletBean() throws ServletException { getServletContext().log("Initializing Spring FrameworkServlet '" + getServletName() + "'"); if (logger.isInfoEnabled()) { logger.info("FrameworkServlet '" + getServletName() + "': initialization started"); } long startTime = System.currentTimeMillis(); try { this.webApplicationContext = initWebApplicationContext(); // 模板方法 initFrameworkServlet(); } catch (ServletException | RuntimeException ex) { logger.error("Context initialization failed", ex); throw ex; } if (logger.isInfoEnabled()) { long elapsedTime = System.currentTimeMillis() - startTime; logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " + elapsedTime + " ms"); } }
这里核心代码就两句,一个是初始化WebApplicationContext,另外一句用于初始化FrameworkServlet,也是模板方法,子类覆盖在这里面作一些初始化操做。好像子类并无使用它,因此他的主要职责仍是初始化WebApplicationContextthis
protected WebApplicationContext initWebApplicationContext() { // 获取rootContext WebApplicationContext rootContext = WebApplicationContextUtils.getWebApplicationContext(getServletContext()); WebApplicationContext wac = null; // 1.若是已经经过构造方法设置了webApplicationContext,主要是Servlet3.0环境中 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) { //2.查看容器是否已经存在了,当webApplicationContext已经存在ServletContext中时, // 经过配置在Servlet中的contextAttribute参数获取 wac = findWebApplicationContext(); } if (wac == null) { // 3.若是webApplicationContext尚未建立,则建立一个 wac = createWebApplicationContext(rootContext); } if (!this.refreshEventReceived) { //当ContextRefreshedEvent事件没有触发时调用次方法,模板方法,能够在子类重写 onRefresh(wac); } if (this.publishContext) { // 将webApplicationContext保持到ServletContext中 String attrName = getServletContextAttributeName(); getServletContext().setAttribute(attrName, wac); if (logger.isTraceEnabled()) { logger.trace("Published WebApplicationContext of servlet '" + getServletName() + "' as ServletContext attribute [" + attrName + "]"); } } return wac; }
initWebApplicationContext主要作了三件事:spa
1.获取spring的跟容器rootContext。debug
默认状况下spring会将本身的容器设置成ServletContext的一个属性,key定义以下
String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";
因此获取跟容器代码为:
Object attr = sc.getAttribute(attrName);
2.设置webApplicationContext并根据状况调用onRefresh方法。
protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) { //建立类型 即XmlWebApplicationContext.class Class<?> contextClass = getContextClass(); if (logger.isTraceEnabled()) { logger.trace("Servlet '" + getServletName() + "' will create custom WebApplicationContext context of class '" + contextClass.getName() + "'" + ", 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"); } //具体建立实例化 ConfigurableWebApplicationContext wac = (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass); //设置环境 wac.setEnvironment(getEnvironment()); //设置父容器 wac.setParent(parent); String configLocation = getContextConfigLocation(); if (configLocation != null) { //将设置的configLocation参数传给wac wac.setConfigLocation(configLocation); } configureAndRefreshWebApplicationContext(wac); return wac; }
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) { 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 if (this.contextId != null) { wac.setId(this.contextId); } else { // Generate default id... wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX + ObjectUtils.getDisplayString(getServletContext().getContextPath()) + '/' + getServletName()); } } wac.setServletContext(getServletContext()); wac.setServletConfig(getServletConfig()); wac.setNamespace(getNamespace()); // 添加ContextRefreshEvent事件的监听器 wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener())); // 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 ConfigurableEnvironment env = wac.getEnvironment(); if (env instanceof ConfigurableWebEnvironment) { ((ConfigurableWebEnvironment) env).initPropertySources(getServletContext(), getServletConfig()); } //后置处理器 postProcessWebApplicationContext(wac); applyInitializers(wac); wac.refresh(); }
3.将webApplicationContext设置到ServletContext中。
onRefresh是DispatcherServlet的入口方法,onRefresh调用了initStrategies,在initStrategies中调用9个初始化方法,就是初始化9个组件,后面会详细介绍。
@Override protected void onRefresh(ApplicationContext context) { initStrategies(context); }
protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); if (logger.isDebugEnabled()) { if (this.disableLoggingRequestDetails) { logger.debug("Logging request parameters and headers is OFF."); } else { logger.warn("\n\n" + "!!!!!!!!!!!!!!!!!!!\n" + "Logging request parameters (DEBUG) and headers (TRACE) may show sensitive data.\n" + "If not in development, use the DispatcherServlet property \"disableLoggingRequestDetails=true\",\n" + "or lower the log level.\n" + "!!!!!!!!!!!!!!!!!!!\n"); } } }
SpringMVC的建立过程一个有三个层次,分别是HttpServletBean,FramworkSerlet和DispatcherServlet.
HttpServletBean的做用是将Servlet中的配置参数设置到相应的属性;
FramworkSerlet的做用是初始化webApplicationContext;
DispatcherServlet的做用是初始化自身的9个组件
总的来讲结构简单实现复杂。