没头苍蝇网

springmvc 启动过程

springmvc 启动过程

dispatcher-servlet.xml

contextConfigLocation/WEB-INF/applicationContext.xmlorg.springframework.web.context.ContextLoaderListenerdispatcherorg.springframework.web.servlet.DispatcherServlet1dispatcher/
ContextLoader 加载ContextLoader.properties文件,内容如下

org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext

通过继承关系可以看到

ContextLoaderListener 继承了ServletContextListener 因此看contextInitialized()方法如何初始化initWebApplicationContext,动过而initWebApplicationContext()在ContextLoader里实现。

ContextLoaderListener#contextInitialized()

public class ContextLoaderListener extends ContextLoader implements ServletContextListener { 	public ContextLoaderListener() { 	}	public ContextLoaderListener(WebApplicationContext context) { 		super(context);	}	/**	 * Initialize the root web application context.	 */	@Override	public void contextInitialized(ServletContextEvent event) { 		initWebApplicationContext(event.getServletContext());	}}

ContextLoader#initWebApplicationContext();

ContextLoader.java/**	 * Initialize Spring's web application context for the given servlet context,动过	 * using the application context provided at construction time, or creating a new one	 * according to the "{ @link #CONTEXT_CLASS_PARAM contextClass}" and	 * "{ @link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.	 * @param servletContext current servlet context	 * @return the new WebApplicationContext	 * @see #ContextLoader(WebApplicationContext)	 * @see #CONTEXT_CLASS_PARAM	 * @see #CONFIG_LOCATION_PARAM	 */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!");		}		servletContext.log("Initializing Spring root WebApplicationContext");		Log logger = LogFactory.getLog(ContextLoader.class);		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) { //根据配置文件实例化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 ioc容器完成初始化					configureAndRefreshWebApplicationContext(cwac, servletContext);				}			}			// 将上下文放在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.isInfoEnabled()) { 				long elapsedTime = System.currentTimeMillis() - startTime;				logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");			}			return this.context;		}		catch (RuntimeException | Error ex) { 			logger.error("Context initialization failed", ex);			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);			throw ex;		}	}


    执行完上述后,由

Tomcat服务器继续执行后续代码过滤器filterStart、动过然后执行配置文件的动过DispatcherServlet

StandardContext.java /**     * Start this component and implement the requirements     * of { @link org.apache.catalina.util.LifecycleBase#startInternal()}.     *     * @exception LifecycleException if this component detects a fatal error     *  that prevents this component from being used     */    @Override    protected synchronized void startInternal() throws LifecycleException { ......// Configure and call application event listeners            if (ok) { //执行listener                if (!listenerStart()) {                     log.error(sm.getString("standardContext.listenerFail"));                    ok = false;                }            }            // Check constraints for uncovered HTTP methods            // Needs to be after SCIs and listeners as they may programmatically            // change constraints            if (ok) {                 checkConstraintsForUncoveredMethods(findConstraints());            }            try {                 // Start manager                Manager manager = getManager();                if ((manager != null) && (manager instanceof Lifecycle)) {                     ((Lifecycle) manager).start();                }            } catch(Exception e) {                 log.error(sm.getString("standardContext.managerFail"), e);                ok = false;            }            // Configure and call application filters            if (ok) { //执行filter                if (!filterStart()) {                     log.error(sm.getString("standardContext.filterFail"));                    ok = false;                }            }            // Load and initialize all "load on startup" servlets//执行servlet            if (ok) {                 if (!loadOnStartup(findChildren())){                     log.error(sm.getString("standardContext.servletFail"));                    ok = false;                }            }......   }

执行类StandardWarpper# private synchronized void initServlet(Servlet servlet)

private synchronized void initServlet(Servlet servlet)            throws ServletException {         if (instanceInitialized && !singleThreadModel) return;        // Call the initialization method of this servlet        try {             instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT,                                              servlet);            if( Globals.IS_SECURITY_ENABLED) {                 boolean success = false;                try {                     Object[] args = new Object[] {  facade };                    SecurityUtil.doAsPrivilege("init",                                               servlet,                                               classType,                                               args);                    success = true;                } finally {                     if (!success) {                         // destroy() will not be called, thus clear the reference now                        SecurityUtil.remove(servlet);                    }                }            } else {                //调用servlet.init();                servlet.init(facade);            }            instanceInitialized = true;            instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,                                              servlet);        } catch (UnavailableException f) {             instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,                                              servlet, f);            unavailable(f);            throw f;        } catch (ServletException f) {             instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,                                              servlet, f);            // If the servlet wanted to be unavailable it would have            // said so, so do not call unavailable(null).            throw f;        } catch (Throwable f) {             ExceptionUtils.handleThrowable(f);            getServletContext().log("StandardWrapper.Throwable", f );            instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,                                              servlet, f);            // If the servlet wanted to be unavailable it would have            // said so, so do not call unavailable(null).            throw new ServletException                (sm.getString("standardWrapper.initException", getName()), f);        }    }


由继承图可以看到,GenericServlet的动过init()方法由HttpServletBean的init()实现。

GenericServlet.java /**     * Called by the servlet container to indicate to a servlet that the servlet     * is 动过being placed into service. See { @link Servlet#init}.     * 

* This implementation stores the { @link ServletConfig} object it receives * from the servlet container for later use. When overriding this form of * the method, call super.init(config). * * @param config * the ServletConfigobject that contains * configuration information for this servlet * @exception ServletException * if an exception occurs that interrupts the servlet's * normal operation * @see UnavailableException */ @Override public void init(ServletConfig config) throws ServletException { this.config = config; this.init(); }/** * A convenience method which can be overridden so that there's no need to * call super.init(config). *

* Instead of overriding { @link #init(ServletConfig)}, simply override this * method and it will be called by * GenericServlet.init(ServletConfig config). The * ServletConfigobject can still be retrieved via * { @link #getServletConfig}. * * @exception ServletException * if an exception occurs that interrupts the servlet's * normal operation */ public void init() throws ServletException { // NOOP by default }

而GenericServlet其自身this.init()方法是空的,需要子类HttpServletBean实现init()

HttpServletBean.java/**	 * Map config parameters onto bean properties of this 动过servlet, and	 * invoke subclass initialization.	 * @throws ServletException if bean properties are invalid (or required	 * properties are missing), or if subclass initialization fails.	 */	@Override	public final void init() throws ServletException { 		// Set bean properties from init parameters.		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;			}		}		// Let subclasses do whatever initialization they like.		initServletBean();	}

FrameworkServlet#initServletBean()

FrameworkServlet.java/**	 * Overridden method of { @link HttpServletBean}, invoked after any bean properties	 * have been set. Creates this servlet's WebApplicationContext.	 */	@Override	protected final void initServletBean() throws ServletException { 		getServletContext().log("Initializing Spring " + getClass().getSimpleName() + " '" + getServletName() + "'");		if (logger.isInfoEnabled()) { 			logger.info("Initializing Servlet '" + getServletName() + "'");		}		long startTime = System.currentTimeMillis();		try {   //创建webApplicationContext,默认由XmlWebApplicationContext实现			this.webApplicationContext = initWebApplicationContext();            //空实现			initFrameworkServlet();		}		catch (ServletException | RuntimeException ex) { 			logger.error("Context initialization failed", ex);			throw ex;		}		if (logger.isDebugEnabled()) { 			String value = this.enableLoggingRequestDetails ?					"shown which may lead to unsafe logging of potentially sensitive data" :					"masked to prevent unsafe logging of potentially sensitive data";			logger.debug("enableLoggingRequestDetails='" + this.enableLoggingRequestDetails +					"': request parameters and headers will be " + value);		}		if (logger.isInfoEnabled()) { 			logger.info("Completed initialization in " + (System.currentTimeMillis() - startTime) + " ms");		}	}

initWebApplicationContext()方法由ContextLoader.java实现。

ContextLoader.java/**	 * Initialize Spring's web application context for the given servlet context,动过	 * using the application context provided at construction time, or creating a new one	 * according to the "{ @link #CONTEXT_CLASS_PARAM contextClass}" and	 * "{ @link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.	 * @param servletContext current servlet context	 * @return the new WebApplicationContext	 * @see #ContextLoader(WebApplicationContext)	 * @see #CONTEXT_CLASS_PARAM	 * @see #CONFIG_LOCATION_PARAM	 */	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!");		}		servletContext.log("Initializing Spring root WebApplicationContext");		Log logger = LogFactory.getLog(ContextLoader.class);		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) { 				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);					}					configureAndRefreshWebApplicationContext(cwac, 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.isInfoEnabled()) { 				long elapsedTime = System.currentTimeMillis() - startTime;				logger.info("Root WebApplicationContext initialized in " + elapsedTime + " ms");			}			return this.context;		}		catch (RuntimeException | Error ex) { 			logger.error("Context initialization failed", ex);			servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);			throw ex;		}	}
this.context = createWebApplicationContext(servletContext);
/**	 * Instantiate the root WebApplicationContext for this loader, either the	 * default context class or a custom context class if specified.	 * 

This implementation expects custom contexts to implement the * { @link ConfigurableWebApplicationContext} interface. * Can be overridden in subclasses. *

In addition, { @link #customizeContext} gets called prior to refreshing the * context, allowing subclasses to perform custom modifications to the context. * @param sc current servlet context * @return the root WebApplicationContext * @see ConfigurableWebApplicationContext */ protected WebApplicationContext createWebApplicationContext(ServletContext sc) { ClasscontextClass = 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); }


   configureAndRefreshWebApplicationContext(wac);

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);		String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);		if (configLocationParam != null) { 			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		ConfigurableEnvironment env = wac.getEnvironment();		if (env instanceof ConfigurableWebEnvironment) { 			((ConfigurableWebEnvironment) env).initPropertySources(sc, null);		}		customizeContext(sc, wac);//调用AbstractApplicationContext  refresh()方法		wac.refresh();	}

AbstractApplicationContext#refresh()

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


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

AbstractApplicationContext.java/**	 * Finish the refresh of this context, invoking the LifecycleProcessor's	 * onRefresh() method and publishing the	 * { @link org.springframework.context.event.ContextRefreshedEvent}.	 */	protected void finishRefresh() { 		// Clear context-level resource caches (such as ASM metadata from scanning).		clearResourceCaches();		// Initialize lifecycle processor for this context.		initLifecycleProcessor();		// Propagate refresh to lifecycle processor first.		getLifecycleProcessor().onRefresh();		// Publish the final event.		publishEvent(new ContextRefreshedEvent(this));		// Participate in LiveBeansView MBean, if active.		LiveBeansView.registerApplicationContext(this);	}/**	 * Publish the given event to all listeners.	 * 

Note: Listeners get initialized after the MessageSource, to be able * to access it within listener implementations. Thus, MessageSource * implementations cannot publish events. * @param event the event to publish (may be application-specific or a * standard framework event) */ @Override public void publishEvent(ApplicationEvent event) { publishEvent(event, null); }/** * Publish the given event to all listeners. * @param event the event to publish (may be an { @link ApplicationEvent} * or a payload object to be turned into a { @link PayloadApplicationEvent}) * @param eventType the resolved event type, if known * @since 4.2 */ protected void publishEvent(Object event, @Nullable ResolvableType eventType) { Assert.notNull(event, "Event must not be null"); // Decorate event as an ApplicationEvent if necessary ApplicationEvent applicationEvent; if (event instanceof ApplicationEvent) { applicationEvent = (ApplicationEvent) event; } else { applicationEvent = new PayloadApplicationEvent<>(this, event); if (eventType == null) { eventType = ((PayloadApplicationEvent) applicationEvent).getResolvableType(); } } // Multicast right now if possible - or lazily once the multicaster is initialized if (this.earlyApplicationEvents != null) { this.earlyApplicationEvents.add(applicationEvent); } else { getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType); } // Publish event via parent context as well... if (this.parent != null) { if (this.parent instanceof AbstractApplicationContext) { ((AbstractApplicationContext) this.parent).publishEvent(event, eventType); } else { this.parent.publishEvent(event); } } }


getApplicationEventMulticaster().multicastEvent(applicationEvent, eventType);

SimpleApplicationEventMulticaster.java

SimpleApplicationEventMulticaster.java@Override	public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) { 		ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));		Executor executor = getTaskExecutor();		for (ApplicationListenerlistener : getApplicationListeners(event, type)) { 			if (executor != null) { 				executor.execute(() ->invokeListener(listener, event));			}			else { 				invokeListener(listener, event);			}		}	}	private ResolvableType resolveDefaultEventType(ApplicationEvent event) { 		return ResolvableType.forInstance(event);	}


      else {
         invokeListener(listener, event);
    }

/**	 * Invoke the given listener with the given event.	 * @param listener the ApplicationListener to invoke	 * @param event the current event to propagate	 * @since 4.1	 */	protected void invokeListener(ApplicationListenerlistener, ApplicationEvent event) { 		ErrorHandler errorHandler = getErrorHandler();		if (errorHandler != null) { 			try { 				doInvokeListener(listener, event);			}			catch (Throwable err) { 				errorHandler.handleError(err);			}		}		else { 			doInvokeListener(listener, event);		}	}


   else {
      doInvokeListener(listener, event);
   }
 

@SuppressWarnings({ "rawtypes", "unchecked"})	private void doInvokeListener(ApplicationListener listener, ApplicationEvent event) { 		try { 			listener.onApplicationEvent(event);		}		catch (ClassCastException ex) { 			String msg = ex.getMessage();			if (msg == null || matchesClassCastMessage(msg, event.getClass())) { 				// Possibly a lambda-defined listener which we could not resolve the generic event type for				// ->let's suppress the exception and just log a debug message.				Log logger = LogFactory.getLog(getClass());				if (logger.isTraceEnabled()) { 					logger.trace("Non-matching event type for listener: " + listener, ex);				}			}			else { 				throw ex;			}		}	}


   try {
      listener.onApplicationEvent(event);
   }
 

SourceFilteringListener.java

@Override	public void onApplicationEvent(ApplicationEvent event) { 		if (event.getSource() == this.source) { 			onApplicationEventInternal(event);		}	}/**	 * Actually process the event, after having filtered according to the	 * desired event source already.	 * 

The default implementation invokes the specified delegate, if any. * @param event the event to process (matching the specified source) */ protected void onApplicationEventInternal(ApplicationEvent event) { if (this.delegate == null) { throw new IllegalStateException( "Must specify a delegate object or override the onApplicationEventInternal method"); }//这个this.delegate又委托GenericApplicationListenerAdapter类的onApplicationEvent方法 this.delegate.onApplicationEvent(event); }

GenericApplicationListenerAdapter.java	@Override	public void onApplicationEvent(ApplicationEvent event) { //这个this.delegate又委托ContextRefreshListener类的onApplicationEvent方法		this.delegate.onApplicationEvent(event);	}

事件源XmlWebApplicationContext

事件ContextRefreshedEvent

监听器 ContextRefreshListener

FrameworkServlet.java

FrameworkServlet.java/**	 * ApplicationListener endpoint that receives events from this servlet's WebApplicationContext	 * only, delegating to { @code onApplicationEvent} on the FrameworkServlet instance.	 *///内部类	private class ContextRefreshListener implements ApplicationListener{ 		@Override		public void onApplicationEvent(ContextRefreshedEvent event) { 			FrameworkServlet.this.onApplicationEvent(event);		}	}
FrameworkServlet.java/**	 * Callback that receives refresh events from this servlet's WebApplicationContext.	 * 

The default implementation calls { @link #onRefresh}, * triggering a refresh of this servlet's context-dependent state. * @param event the incoming ApplicationContext event */ public void onApplicationEvent(ContextRefreshedEvent event) { this.refreshEventReceived = true; synchronized (this.onRefreshMonitor) { onRefresh(event.getApplicationContext()); } } /** * Template method which can be overridden to add servlet-specific refresh work. * Called after successful context refresh. *

This implementation is empty. * @param context the current WebApplicationContext * @see #refresh() */ protected void onRefresh(ApplicationContext context) { // For subclasses: do nothing by default. }

因为DispatcherServlet extends FrameworkServlet,所以执行子类DispatcherServlet#onRefresh()

DispatcherServlet.java/**	 * This implementation calls { @link #initStrategies}.	 */	@Override	protected void onRefresh(ApplicationContext context) { 		initStrategies(context);	}	/**	 * Initialize the strategy objects that this servlet uses.	 * 

May be overridden in subclasses in order to initialize further strategy objects. */ protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); }

initStrategies就是springmvc大家熟悉的流程了。。动过。动过动过

未经允许不得转载:没头苍蝇网 » springmvc 启动过程