SpringBoot、SpringMvc 和SpringMvc核心容器创建及DispatcherServlet运行原理

该篇博文前面描述的是基于xml配置,非SpringBoot项目。

一般项目中使用Tomcat作为Web容器时会有三个容器:

  • ServletContext-Tomcat启动时创建,
  • Spring容器-Root WebApplicationContext-IOC容器
  • SpringMVC容器。`

Spring容器以属性(org.springframework.web.context.WebApplicationContext.ROOT)-值(Root WebApplicationContext)放置在ServletContext中,SpringMVC容器以属性(org.springframework.web.servlet.FrameworkServlet.CONTEXT.springMVC)-值(WebApplicationContext)放置在ServletContext容器中。

同时,Spring容器是SpringMVC容器的父容器!

07EDE94D-B2DB-19CA-5A78-5FD2BD501751.jpeg

【1】Spring容器的创建

Tomcat启动会检测classpath是否有WebApplicationInitializer,然后创建ServletContext之后读取web.xml中节点。其中ContextLoaderListener会创建Spring Root WebApplicationContext

首先看下图,Tomcat的StandardContext调用listenerStart()方法(本图为创建Spring Root WebApplicaitonContext后):

8F760F5D-4A60-1B7C-0246-01FE9DAD53E0.png

① ContextLoaderListener.contextInitialized()方法

//初始化Spring Root WebApplicationContext
	@Override
	public void contextInitialized(ServletContextEvent event) {
		//参考② 
		initWebApplicationContext(event.getServletContext());
	}

② ContextLoader.initWebApplicationContext()方法源码如下:

// 这里ServletContext为org.apache.catalina.core.ApplicationContextFacade@7824f26a
//ApplicationContextFacade:从Web应用程序中屏蔽内部应用程序上下文对象的外观对象
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
		//如果发现已经创建过root web application context将会抛出异常
		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);
		//打印日志信息,表明开始创建Spring root WebApplicationContext
		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) {
			//使用servletContext创建Root WebApplicationContext
				this.context = createWebApplicationContext(servletContext);//参考2.1
			}
			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.
						//给Root WebApplicationContext设置父容器,默认返回null
						//通常这里你可以设想父容器为Servlet
						ApplicationContext parent = loadParentContext(servletContext);
						cwac.setParent(parent);
					}
					//配置并刷新Root WebApplicationContext 参考③
					configureAndRefreshWebApplicationContext(cwac, servletContext);
				}
			}
//以org.springframework.web.context.WebApplicationContext.ROOT为属性,放到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;
		}
	}

这里分别说明一下WebApplicationContext和ServletContext。

javax.servlet.ServletContext如下图所示:

5D8CF1E6-4544-B337-B2BF-0B209509D884.jpeg

Tomcat作为WebServer项目中,你可以理解为项目中使用到的ServletContext即为org.apache.catalina.core.ApplicationContextFacade

那么Spring中的ApplicationContext呢?如下图所示:

3F293490-EFB7-72F0-1FD6-D8396B238F82.jpeg

6934AEB3-652F-0609-F56E-74FB4924227E.jpeg

(2.1)ContextLoader.createWebApplicationContext

源码如下:

/**
	 * Instantiate the root WebApplicationContext for this loader, either the
	 * default context class or a custom context class if specified.
	 * <p>This implementation expects custom contexts to implement the
	 * {@link ConfigurableWebApplicationContext} interface.
	 * Can be overridden in subclasses.
	 * <p>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) {
	//根据上下文决定contextClass 
		Class<?> contextClass = determineContextClass(sc);
		if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
			throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
					"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
		}
		//使用反射创建ConfigurableWebApplicationContext实例
		return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
	}

如下项目使用了xml,这里返回的为XmlWebApplicationContext:

C1CB16F3-B3DD-6A5B-1752-4B95DFE8DCFF.png


③ ContextLoader.configureAndRefreshWebApplicationContext()方法

源码如下:

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);
			}
			// id:org.springframework.web.context.WebApplicationContext:
			else {
				// Generate default id...
				wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
						ObjectUtils.getDisplayString(sc.getContextPath()));
			}
		}
		// 设置关联的上下文ApplicationContextFacade
		wac.setServletContext(sc);
		//设置配置文件classpath:applicationContext.xml
		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);
		}
/*
在配置位置被提供给上下文之后,但是在上下文被<em>刷新</em>之前,
自定义由ContextLoader创建的{@link ConfigurableWebApplicationContext}。
*/
		//参考④
		customizeContext(sc, wac);
		//重要方法!参考⑤ 
		wac.refresh();
	}

④ ContextLoader.customizeContext()

遍历系统中的ApplicationContextInitializer,调用其initialize方法:

protected void customizeContext(ServletContext sc, ConfigurableWebApplicationContext wac) {
		List<Class<ApplicationContextInitializer<ConfigurableApplicationContext>>> initializerClasses =
				determineContextInitializerClasses(sc);

		for (Class<ApplicationContextInitializer<ConfigurableApplicationContext>> initializerClass : initializerClasses) {
			Class<?> initializerContextClass =
					GenericTypeResolver.resolveTypeArgument(initializerClass, ApplicationContextInitializer.class);
			if (initializerContextClass != null && !initializerContextClass.isInstance(wac)) {
				throw new ApplicationContextException(String.format(
						"Could not apply context initializer [%s] since its generic parameter [%s] " +
						"is not assignable from the type of application context used by this " +
						"context loader: [%s]", initializerClass.getName(), initializerContextClass.getName(),
						wac.getClass().getName()));
			}
			this.contextInitializers.add(BeanUtils.instantiateClass(initializerClass));
		}

		AnnotationAwareOrderComparator.sort(this.contextInitializers);
		for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
			initializer.initialize(wac);
		}
	}

⑤ 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.
			//告诉子类去刷新内部Bean 工程,这一步会加载一些bean定义放到BeanFactory中
			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.
				//bean工厂后置处理--允许创建实例后再进行修改
				//参考⑦
				postProcessBeanFactory(beanFactory);

				// Invoke factory processors registered as beans in the context.
//初始化并按次序(如果设置了order)调用所有已注册的BeanFactoryPostProcessors
				invokeBeanFactoryPostProcessors(beanFactory);

				// Register bean processors that intercept bean creation.
//初始化并按次序(如果设置了order)调用所有已注册的BeanPostProcessors
				//参考 ⑧
				registerBeanPostProcessors(beanFactory);

				// Initialize message source for this context.
				//读取properties的,并支持国际化的bean
				initMessageSource();

				// Initialize event multicaster for this context.
				//初始化程序事件广播器--单例
				//尝试从BeanFactory中根据属性applicationEventMulticaster获取;
				//如果没有则创建一个SimpleApplicationEventMulticaster并注册到BeanFactory
				initApplicationEventMulticaster();

				// Initialize other special beans in specific context subclasses.
				// 在特定上下文子类中初始化其他特殊bean
				//参考⑨
				onRefresh();

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

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

				// Last step: publish corresponding event.
				//参考 (12)
				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();
			}
		}
	}

⑥ AbstractApplicationContext.prepareBeanFactory()方法

注册了一些基础的、项目中很可能使用的、为其他bean提供服务的bean。源码如下:

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		// Tell the internal bean factory to use the context's class loader etc.
		beanFactory.setBeanClassLoader(getClassLoader());
		beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
		beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

		// Configure the bean factory with context callbacks.
		beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
		beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
		beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
		beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
		beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
		beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

		// BeanFactory interface not registered as resolvable type in a plain factory.
		// MessageSource registered (and found for autowiring) as a bean.
		beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
		beanFactory.registerResolvableDependency(ResourceLoader.class, this);
		beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
		beanFactory.registerResolvableDependency(ApplicationContext.class, this);

		// Register early post-processor for detecting inner beans as ApplicationListeners.
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

		// Detect a LoadTimeWeaver and prepare for weaving, if found.
		if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
			beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
			// Set a temporary ClassLoader for type matching.
			beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
		}

		// Register default environment beans.
		if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
		}
		if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
			beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
		}
	}

⑦ AbstractRefreshableWebApplicationContext.postProcessBeanFactory()方法

源码如下:

/**
	 * Register request/session scopes, a {@link ServletContextAwareProcessor}, etc.
	 */
	@Override
	protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
		beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
		beanFactory.ignoreDependencyInterface(ServletContextAware.class);
		beanFactory.ignoreDependencyInterface(ServletConfigAware.class);

		WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
		WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
	}

⑧ AbstractApplicationContext.registerBeanPostProcessors()

源码如下:

/**
	 * Instantiate and invoke all registered BeanPostProcessor beans,
	 * respecting explicit order if given.
	 * <p>Must be called before any instantiation of application beans.
	 */
	protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
		PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
	}

其调用了PostProcessorRegistrationDelegate的registerBeanPostProcessors方法:

public static void registerBeanPostProcessors(
			ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {

		String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true, false);

		// Register BeanPostProcessorChecker that logs an info message when
		// a bean is created during BeanPostProcessor instantiation, i.e. when
		// a bean is not eligible for getting processed by all BeanPostProcessors.
		int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
		beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));

		// Separate between BeanPostProcessors that implement PriorityOrdered,
		// Ordered, and the rest.
		List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
		List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
		List<String> orderedPostProcessorNames = new ArrayList<>();
		List<String> nonOrderedPostProcessorNames = new ArrayList<>();
		for (String ppName : postProcessorNames) {
			if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
				BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
				priorityOrderedPostProcessors.add(pp);
				if (pp instanceof MergedBeanDefinitionPostProcessor) {
					internalPostProcessors.add(pp);
				}
			}
			else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
				orderedPostProcessorNames.add(ppName);
			}
			else {
				nonOrderedPostProcessorNames.add(ppName);
			}
		}

		// First, register the BeanPostProcessors that implement PriorityOrdered.
		sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);

		// Next, register the BeanPostProcessors that implement Ordered.
		List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>();
		for (String ppName : orderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			orderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		sortPostProcessors(orderedPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, orderedPostProcessors);

		// Now, register all regular BeanPostProcessors.
		List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>();
		for (String ppName : nonOrderedPostProcessorNames) {
			BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
			nonOrderedPostProcessors.add(pp);
			if (pp instanceof MergedBeanDefinitionPostProcessor) {
				internalPostProcessors.add(pp);
			}
		}
		registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);

		// Finally, re-register all internal BeanPostProcessors.
		sortPostProcessors(internalPostProcessors, beanFactory);
		registerBeanPostProcessors(beanFactory, internalPostProcessors);

		// Re-register post-processor for detecting inner beans as ApplicationListeners,
		// moving it to the end of the processor chain (for picking up proxies etc).
		beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
	}

⑨ AbstractRefreshableWebApplicationContext.onRefresh()

源码如下:

/**
	 * Initialize the theme capability.
	 */
	@Override
	protected void onRefresh() {
		this.themeSource = UiApplicationContextUtils.initThemeSource(this);
	}

UiApplicationContextUtils.initThemeSource(this)如下:

/**
	 * Initialize the ThemeSource for the given application context,
	 * autodetecting a bean with the name "themeSource". If no such
	 * bean is found, a default (empty) ThemeSource will be used.
	 * @param context current application context
	 * @return the initialized theme source (will never be {@code null})
	 * @see #THEME_SOURCE_BEAN_NAME
	 */
	public static ThemeSource initThemeSource(ApplicationContext context) {
		if (context.containsLocalBean(THEME_SOURCE_BEAN_NAME)) {
			ThemeSource themeSource = context.getBean(THEME_SOURCE_BEAN_NAME, ThemeSource.class);
			// Make ThemeSource aware of parent ThemeSource.
			if (context.getParent() instanceof ThemeSource && themeSource instanceof HierarchicalThemeSource) {
				HierarchicalThemeSource hts = (HierarchicalThemeSource) themeSource;
				if (hts.getParentThemeSource() == null) {
					// Only set parent context as parent ThemeSource if no parent ThemeSource
					// registered already.
					hts.setParentThemeSource((ThemeSource) context.getParent());
				}
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Using ThemeSource [" + themeSource + "]");
			}
			return themeSource;
		}
		else {
			// Use default ThemeSource to be able to accept getTheme calls, either
			// delegating to parent context's default or to local ResourceBundleThemeSource.
			HierarchicalThemeSource themeSource = null;
			if (context.getParent() instanceof ThemeSource) {
				themeSource = new DelegatingThemeSource();
				themeSource.setParentThemeSource((ThemeSource) context.getParent());
			}
			else {
				themeSource = new ResourceBundleThemeSource();
			}
			if (logger.isDebugEnabled()) {
				logger.debug("Unable to locate ThemeSource with name '" + THEME_SOURCE_BEAN_NAME +
						"': using default [" + themeSource + "]");
			}
			return themeSource;
		}
	}

(10)AbstractApplicationContext.registerListeners()

源码如下:

/**
 * Add beans that implement ApplicationListener as listeners.
 * Doesn't affect other listeners, which can be added without being beans.
 */
protected void registerListeners() {
	// Register statically specified listeners first.
		//把监听器放入应用事件广播器中
	for (ApplicationListener<?> listener : getApplicationListeners()) {
		getApplicationEventMulticaster().addApplicationListener(listener);
	}

	// Do not initialize FactoryBeans here: We need to leave all regular beans
	// uninitialized to let post-processors apply to them!
	//获取所有需要被监听的BeanName
	String[] listenerBeanNames = getBeanNamesForType(ApplicationListener.class, true, false);
	//遍历所有BeanName
	for (String listenerBeanName : listenerBeanNames) {
		// Add a listener bean to be notified of all events.
		getApplicationEventMulticaster().addApplicationListenerBean(listenerBeanName);
	}

	// Publish early application events now that we finally have a multicaster...
	Set<ApplicationEvent> earlyEventsToProcess = this.earlyApplicationEvents;
	this.earlyApplicationEvents = null;
	if (earlyEventsToProcess != null) {
		for (ApplicationEvent earlyEvent : earlyEventsToProcess) {
			//广播事件给监听
			getApplicationEventMulticaster().multicastEvent(earlyEvent);
		}
	}
}

(11)AbstractApplicationContext.finishBeanFactoryInitialization()

/**
* Finish the initialization of this context's bean factory,
 * initializing all remaining singleton beans.
 */
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	// Initialize conversion service for this context.--conversionService
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME) &&
			beanFactory.isTypeMatch(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class)) {
		beanFactory.setConversionService(
				beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME, ConversionService.class));
	}

	// Register a default embedded value resolver if no bean post-processor
	// (such as a PropertyPlaceholderConfigurer bean) registered any before:
	// at this point, primarily for resolution in annotation attribute values.
	if (!beanFactory.hasEmbeddedValueResolver()) {
		beanFactory.addEmbeddedValueResolver(strVal -> getEnvironment().resolvePlaceholders(strVal));
	}

	// Initialize LoadTimeWeaverAware beans early to allow for registering their transformers early.
	String[] weaverAwareNames = beanFactory.getBeanNamesForType(LoadTimeWeaverAware.class, false, false);
	for (String weaverAwareName : weaverAwareNames) {
		getBean(weaverAwareName);
	}

	// Stop using the temporary ClassLoader for type matching.
	beanFactory.setTempClassLoader(null);

	// Allow for caching all bean definition metadata, not expecting further changes.
	beanFactory.freezeConfiguration();

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

(12)AbstractApplicationContext.finishRefresh()

源码如下:

/**
	 * 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.
		//Initialize the LifecycleProcessor.
	 //Uses DefaultLifecycleProcessor if none defined in the context.
		initLifecycleProcessor();

		// Propagate refresh to lifecycle processor first.
		//首先将刷新传播到生命周期处理器
		getLifecycleProcessor().onRefresh();

		// Publish the final event.
		//参考(13)
		publishEvent(new ContextRefreshedEvent(this));

		// Participate in LiveBeansView MBean, if active.
		LiveBeansView.registerApplicationContext(this);
	}

(13)AbstractApplicationContext.publishEvent()

如下所示:

/**
	 * Publish the given event to all listeners.
	 * <p>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);
	}

调用的publishEvent(event,null)如下所示:

protected void publishEvent(Object event, @Nullable ResolvableType eventType) {
		Assert.notNull(event, "Event must not be null");
		if (logger.isTraceEnabled()) {
			logger.trace("Publishing event in " + getDisplayName() + ": " + event);
		}

		// 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 {
		//applicationEvent==ContextRefreshedEvent
		//Multicast the given application event to appropriate listeners. 
//If the eventType is null, a default type is builtbased on the event instance.

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

至此,Spring容器创建、配置并刷新完成!!!


【2】SpringMVC容器创建

SpringMVC的核心是DispatcherServlet,其是一个Servlet。首先要注意Servlet的三个标准方法:init(),service()和destroy()。

DispatcherServlet类继承如下:

F1A38040-B37C-A501-EA8A-621003814F85.jpeg

DispatcherServlet是没有init()方法的,其继承父类HttpServletBean.init()方法。

DispatcherServlet也没有service()方法,其继承父类FrameworkServlet.service()方法。

这里主要研究这两个方法前后做了什么。

【3】HttpServletBean.init()

(1)SpringMVC容器创建

创建完IOC容器后就该创建SpringMVC容器。

51FA00B8-60F5-CEE0-ED1E-CE9244E5D352.jpeg

首先Tomcat调用无参构造函数,初始化DispatcherServlet实例。StandardContext 实例化servlet之后,接着初始化该servlet。

DispatcherServlet自身没有init()方法,其继承自父类HttpServletBean,这时首先调用HttpServletBean.init()方法。

init 方法的执行时刻其实与 servlet 的配置有关。可以看到以下代码的load-on-startup结点,如果结点的值大于等于 0,则在 Servlet 实例化的时候执行,间隔时间由具体的值决定,值越大,则越迟执行。如果小于 0 或者没有配置,则在第一次请求的时候才同步执行 , 注意 init 方法只执行一次。

<load-on-startup>1</load-on-startup>

HttpServletBean.init()源码如下:

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

		// 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.
		//这里我们要关注这个!FrameworkServlet.initServletBean() --参考2
		initServletBean();

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

(2) FrameworkServlet.initServletBean()

然后开始执行FrameworkServlet.initServletBean() 方法,其重写了父类HttpServletBean.initServletBean方法,源码如下:

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 FrameworkServlet '" + getServletName() + "'");
		if (this.logger.isInfoEnabled()) {
			this.logger.info("FrameworkServlet '" + getServletName() + "': initialization started");
		}
		long startTime = System.currentTimeMillis();

		try {
			// 初始化WebApplicationContext--参考3
			this.webApplicationContext = initWebApplicationContext();
			//初始化FrameworkServlet--参考4
			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");
		}
	}

这段代码很重要,先初始化WebApplicationContext,然后初始化FrameworkServlet!


(3)FrameworkServlet.initWebApplicationContext()

Initialize and publish the WebApplicationContext for this servlet.

源码如下:

protected WebApplicationContext initWebApplicationContext() {
		// 根据xml获取Root WebApplicationContext--XmlWebApplicationContext
		//现获取父容器
		WebApplicationContext rootContext =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext());
		WebApplicationContext wac = null;

		//判断项目中是否已经存在DispatcherServlet.webApplicationContext 
		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) {
			// No context instance was injected at construction time -> see if one
			// has been registered in the servlet context. If one exists, it is assumed
			// that the parent context (if any) has already been set and that the
			// user has performed any initialization such as setting the context id
			wac = findWebApplicationContext();
			//尝试从servlet context 查找一个WebApplicationContext--3.1
		}
		if (wac == null) {
			// No context instance is defined for this servlet -> create a local one
			wac = createWebApplicationContext(rootContext);
			//根据rootContext创建一个WebApplicationContext--3.2
		}

/** Flag used to detect whether onRefresh has already been called */
// private boolean refreshEventReceived = false;

		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.
			onRefresh(wac);
			//这个方法很重要!!!
		}
	
//使用属性org.springframework.web.servlet.FrameworkServlet.CONTEXT.springMVC
//放到org.apache.catalina.core.ApplicationContext中
		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;
	}

获取根容器源码如下:

WebApplicationContextUtils.getWebApplicationContext

@Nullable
	public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
		return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
	}
	//ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE:
	//org.springframework.web.context.WebApplicationContext.ROOT

(3.1)FrameworkServlet.findWebApplicationContext()方法

Retrieve a {@code WebApplicationContext} from the {@code ServletContext} attribute with the {@link #setContextAttribute configured name}。

@Nullable
	protected WebApplicationContext findWebApplicationContext() {
		String attrName = getContextAttribute();
		if (attrName == null) {
			return null;
		}
		WebApplicationContext wac =
				WebApplicationContextUtils.getWebApplicationContext(getServletContext(), attrName);
		if (wac == null) {
			throw new IllegalStateException("No WebApplicationContext found: initializer not registered?");
		}
		return wac;
	}

(3.2)createWebApplicationContext

Instantiate the WebApplicationContext for this servlet, either a default {@link org.springframework.web.context.support.XmlWebApplicationContext} or a {@link #setContextClass custom context class}, if set.

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

Do not forget to register this servlet instance as application listener on the created context (for triggering its {@link #onRefresh callback}, and to call {@link org.springframework.context.ConfigurableApplicationContext#refresh()} before returning the context instance.

源码如下:

protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
		//org.springframework.web.context.support.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");
		}
		//根据contextClass获取实例并强转为ConfigurableWebApplicationContext 
		ConfigurableWebApplicationContext wac =
				(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
		//设置环境
		wac.setEnvironment(getEnvironment());
		//设置父容器--initWebApplicationContext里面的rootContext
		wac.setParent(parent);
		//配置文件路径classpath:spring-mvc.xml
		String configLocation = getContextConfigLocation();
		if (configLocation != null) {
			wac.setConfigLocation(configLocation);
		}
		//配置并刷新创建的wac-3.3
		configureAndRefreshWebApplicationContext(wac);

		return wac;
	}

(3.3)configureAndRefreshWebApplicationContext

源码如下:

protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac) {

		//设置id:org.springframework.web.context.WebApplicationContext:/springMVC
		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());
		//setNamespace:springMVC-servlet
		wac.setNamespace(getNamespace());
		//添加监听
		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());
		}
//在刷新和激活该servlet的上下文之前,对给定的wac进行后期处理。默认空方法
		postProcessWebApplicationContext(wac);
		//参考 3.4
		applyInitializers(wac);
		//参考3.5
		wac.refresh();
	}

(3.4)applyInitializers

Delegate the WebApplicationContext before it is refreshed to any {@link ApplicationContextInitializer} instances specified by the “contextInitializerClasses” servlet init-param.

源码如下:

protected void applyInitializers(ConfigurableApplicationContext wac) {
		String globalClassNames = getServletContext().getInitParameter(ContextLoader.GLOBAL_INITIALIZER_CLASSES_PARAM);
		if (globalClassNames != null) {
			for (String className : StringUtils.tokenizeToStringArray(globalClassNames, INIT_PARAM_DELIMITERS)) {
				this.contextInitializers.add(loadInitializer(className, wac));
			}
		}

		if (this.contextInitializerClasses != null) {
			for (String className : StringUtils.tokenizeToStringArray(this.contextInitializerClasses, INIT_PARAM_DELIMITERS)) {
				this.contextInitializers.add(loadInitializer(className, wac));
			}
		}

		AnnotationAwareOrderComparator.sort(this.contextInitializers);
		for (ApplicationContextInitializer<ConfigurableApplicationContext> initializer : this.contextInitializers) {
			initializer.initialize(wac);
		}
	}

(3.5)AbstractApplicationContext.refresh()

再次调用AbstractApplicationContext.refresh()!上面创建Root WebApplicationContext时最后一步就调用了该方法!

这里需要注意的是在 wac.refresh()方法中,有个方法调用至关重要:

//registerApplicationContext
publishEvent(new ContextRefreshedEvent(this));

因为FrameWorkServelt有个私有内部类ContextRefreshListener :

/**
	 * ApplicationListener endpoint that receives events from this servlet's WebApplicationContext
	 * only, delegating to {@code onApplicationEvent} on the FrameworkServlet instance.
	 */
	private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {

		@Override
		public void onApplicationEvent(ContextRefreshedEvent event) {
			//参考(3.6)
			FrameworkServlet.this.onApplicationEvent(event);
		}
	}

(3.6)FrameworkServlet.onApplicationEvent()

其源码如下:

/**
	 * Callback that receives refresh events from this servlet's WebApplicationContext.
	 * <p>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;
		//参考(3.7)
		onRefresh(event.getApplicationContext());
	}

(3.7)DispatcherServlet.onRefresh()

源码如下:

/**
	 * This implementation calls {@link #initStrategies}.
	 */
	@Override
	protected void onRefresh(ApplicationContext context) {
		//初始化策略--参考(3.8)
		initStrategies(context);
	}

(3.8)DispatcherServlet.initStrategies()

源码如下:

/**
* Initialize the strategy objects that this servlet uses.
 * <p>May be overridden in subclasses in order to initialize further strategy objects.
 */
protected void initStrategies(ApplicationContext context) {
	// 上传文件的那个玩意
	initMultipartResolver(context);
	
	//根据beanName--localeResolver从BeanFactory获取LocaleResolver
	//否则返回默认org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver
	initLocaleResolver(context);
	
	//根据beanName--themeResolver从BeanFactory获取
	//否则返回默认org.springframework.web.servlet.theme.FixedThemeResolver
	initThemeResolver(context);

	//Initialize the HandlerMappings used by this class.
	//默认BeanNameUrlHandlerMapping
	initHandlerMappings(context);

	//Initialize the HandlerAdapters used by this class.
	//默认SimpleControllerHandlerAdapter
	initHandlerAdapters(context);

	//Initialize the HandlerExceptionResolver used by this class.
	//we default to no exception resolver.
	initHandlerExceptionResolvers(context);

	//初始化请求视图转换器
	//根据beanName--viewNameTranslator从工厂获取
	//否则返回默认对象DefaultRequestToViewNameTranslator
	initRequestToViewNameTranslator(context);

	//Initialize the ViewResolvers used by this class.
	//default to InternalResourceViewResolver
	initViewResolvers(context);

	//根据beanName-flashMapManager从工厂里面获取
	//默认DefaultFlashMapManager
	initFlashMapManager(context);
}

之后,依次返回3.7,3.6…直到AbstractApplicationContext.publishEvent方法。

方法如下:

/**
* 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");
	if (logger.isTraceEnabled()) {
		logger.trace("Publishing event in " + getDisplayName() + ": " + event);
	}

	// 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...
	//在Spring容器创建过程中,该步跳过了。但是现在SpringMVC父容器为Spring容器!!!
	if (this.parent != null) {
		if (this.parent instanceof AbstractApplicationContext) {
			//调用该方法--参考(3.9)
			((AbstractApplicationContext) this.parent).publishEvent(event, eventType);
		}
		else {
			this.parent.publishEvent(event);
		}
	}
}

(3.9)SimpleApplicationEventMulticaster.multicastEvent

@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
	ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
	for (final ApplicationListener<?> listener : getApplicationListeners(event, type)) {
		Executor executor = getTaskExecutor();
		if (executor != null) {
			executor.execute(() -> invokeListener(listener, event));
		}
		else {
			//调用该方法....
			invokeListener(listener, event);
		}
	}
}

也就是说Spring容器创建过程中调用了一遍AbstractApplicationContext.publishEvent()方法,SpringIOC容器创建过程中调用了两遍AbstractApplicationContext.publishEvent()方法!!

此时FrameworkServlet.configureAndRefreshWebApplicationContext()方法才算结束!返回到(3.2)


(4)initFrameworkServlet

前面初始化了Spring容器和SpringMVC容器,这里初始化FrameworkServlet。

源码如下:

/**
	 * This method will be invoked after any bean properties have been set and
	 * the WebApplicationContext has been loaded. The default implementation is empty;
	 * subclasses may override this method to perform any initialization they require.
	 * @throws ServletException in case of an initialization exception
	 */
	protected void initFrameworkServlet() throws ServletException {
	}

【4】DispatcherServlet运行原理分析

一个Servlet在处理请求的时候具体方法为service,DispatcherServlet继承自父类FrameworkServlet.service()方法。

这里以浏览器发送get请求为例 http://localhost:8080/login

① FrameworkServlet.service()

源码如下:

@Override
	protected void service(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//参考(2)
		HttpMethod httpMethod = HttpMethod.resolve(request.getMethod());
		// 进行方法判断
		if (HttpMethod.PATCH == httpMethod || httpMethod == null) {
			//请求处理
			processRequest(request, response);
		}
		else {
		//参考(3)
			super.service(request, response);
		}
	}

首先获取方法,然后处理请求。


② 获取请求方法

首先获取方法类型名字:

Request.getMethod():

/**
     * Return the HTTP request method used in this Request.
     */
    @Override
    public String getMethod() {
        return coyoteRequest.method().toString();
    }

2801D9C4-17F8-8C1E-F04D-6C65F3C2DB4B.jpeg

其次解析方法名获取HttpMethod:

B9640B18-8185-A446-90DD-FDEB9751B8B0.jpeg


③ HttpServlet.service()方法

源码如下:

protected void service(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {

        String method = req.getMethod();
		// 这里将会走doGet方法,参考(4)
        if (method.equals(METHOD_GET)) {
            long lastModified = getLastModified(req);
            if (lastModified == -1) {
                // servlet doesn't support if-modified-since, no reason
                // to go through further expensive logic
                doGet(req, resp);
            } else {
                long ifModifiedSince;
                try {
                    ifModifiedSince = req.getDateHeader(HEADER_IFMODSINCE);
                } catch (IllegalArgumentException iae) {
                    // Invalid date header - proceed as if none was set
                    ifModifiedSince = -1;
                }
                if (ifModifiedSince < (lastModified / 1000 * 1000)) {
                    // If the servlet mod time is later, call doGet()
                    // Round down to the nearest second for a proper compare
                    // A ifModifiedSince of -1 will always be less
                    maybeSetLastModified(resp, lastModified);
                    doGet(req, resp);
                } else {
                    resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                }
            }
        } else if (method.equals(METHOD_HEAD)) {
            long lastModified = getLastModified(req);
            maybeSetLastModified(resp, lastModified);
            doHead(req, resp);

        } else if (method.equals(METHOD_POST)) {
            doPost(req, resp);

        } else if (method.equals(METHOD_PUT)) {
            doPut(req, resp);

        } else if (method.equals(METHOD_DELETE)) {
            doDelete(req, resp);

        } else if (method.equals(METHOD_OPTIONS)) {
            doOptions(req,resp);

        } else if (method.equals(METHOD_TRACE)) {
            doTrace(req,resp);

        } else {
            //
            // Note that this means NO servlet supports whatever
            // method was requested, anywhere on this server.
            //
            String errMsg = lStrings.getString("http.method_not_implemented");
            Object[] errArgs = new Object[1];
            errArgs[0] = method;
            errMsg = MessageFormat.format(errMsg, errArgs);
            resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED, errMsg);
        }
    }

④ FrameworkServlet.doGet方法

@Override
	protected final void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		//参考 (5)
		processRequest(request, response);
	}

⑤ FrameworkServlet.processRequest()方法

请求处理的核心方法:

/**
	 * Process this request, publishing an event regardless of the outcome.
	 * <p>The actual event handling is performed by the abstract
	 * {@link #doService} template method.
	 */
	protected final void processRequest(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {

		long startTime = System.currentTimeMillis();
		Throwable failureCause = null;

		LocaleContext previousLocaleContext = LocaleContextHolder.getLocaleContext();
		LocaleContext localeContext = buildLocaleContext(request);

		RequestAttributes previousAttributes = RequestContextHolder.getRequestAttributes();
		ServletRequestAttributes requestAttributes = buildRequestAttributes(request, response, previousAttributes);

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.registerCallableInterceptor(FrameworkServlet.class.getName(), new RequestBindingInterceptor());

		initContextHolders(request, localeContext, requestAttributes);

		try {
			// 核心方法 参考(6)
			doService(request, response);
		}
		catch (ServletException | IOException ex) {
			failureCause = ex;
			throw ex;
		}
		catch (Throwable ex) {
			failureCause = ex;
			throw new NestedServletException("Request processing failed", ex);
		}

		finally {
			resetContextHolders(request, previousLocaleContext, previousAttributes);
			if (requestAttributes != null) {
				requestAttributes.requestCompleted();
			}

			if (logger.isDebugEnabled()) {
				if (failureCause != null) {
					this.logger.debug("Could not complete request", failureCause);
				}
				else {
					if (asyncManager.isConcurrentHandlingStarted()) {
						logger.debug("Leaving response open for concurrent processing");
					}
					else {
						this.logger.debug("Successfully completed request");
					}
				}
			}
//发布请求已经被处理事件  参考 (14)
			publishRequestHandledEvent(request, response, startTime, failureCause);
		}
	}

⑥ DispatcherServlet.doService()方法

源码如下:

/**
* Exposes the DispatcherServlet-specific request attributes and delegates to {@link #doDispatch}
 * for the actual dispatching.
 */
@Override
protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {
	if (logger.isDebugEnabled()) {
		String resumed = WebAsyncUtils.getAsyncManager(request).hasConcurrentResult() ? " resumed" : "";
		logger.debug("DispatcherServlet with name '" + getServletName() + "'" + resumed +
				" processing " + request.getMethod() + " request for [" + getRequestUri(request) + "]");
	}

	// Keep a snapshot of the request attributes in case of an include,
	// to be able to restore the original attributes after the include.
	Map<String, Object> attributesSnapshot = null;
	if (WebUtils.isIncludeRequest(request)) {
		attributesSnapshot = new HashMap<>();
		Enumeration<?> attrNames = request.getAttributeNames();
		while (attrNames.hasMoreElements()) {
			String attrName = (String) attrNames.nextElement();
			if (this.cleanupAfterInclude || attrName.startsWith(DEFAULT_STRATEGIES_PREFIX)) {
				attributesSnapshot.put(attrName, request.getAttribute(attrName));
			}
		}
	}

	// Make framework objects available to handlers and view objects.
	request.setAttribute(WEB_APPLICATION_CONTEXT_ATTRIBUTE, getWebApplicationContext());
	request.setAttribute(LOCALE_RESOLVER_ATTRIBUTE, this.localeResolver);
	request.setAttribute(THEME_RESOLVER_ATTRIBUTE, this.themeResolver);
	request.setAttribute(THEME_SOURCE_ATTRIBUTE, getThemeSource());

	if (this.flashMapManager != null) {
		FlashMap inputFlashMap = this.flashMapManager.retrieveAndUpdate(request, response);
		if (inputFlashMap != null) {
			request.setAttribute(INPUT_FLASH_MAP_ATTRIBUTE, Collections.unmodifiableMap(inputFlashMap));
		}
		request.setAttribute(OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
		request.setAttribute(FLASH_MAP_MANAGER_ATTRIBUTE, this.flashMapManager);
	}

	try {
	// 哈哈,在这里  参考(7)
		doDispatch(request, response);
	}
	finally {
		if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			// Restore the original attribute snapshot, in case of an include.
			if (attributesSnapshot != null) {
				restoreAttributesAfterInclude(request, attributesSnapshot);
			}
		}
	}
}

⑦ DispatcherServlet.doDispatch()

源码如下:

/**
 * Process the actual dispatching to the handler.
 * <p>The handler will be obtained by applying the servlet's HandlerMappings in order.
 * The HandlerAdapter will be obtained by querying the servlet's installed HandlerAdapters
 * to find the first that supports the handler class.
 * <p>All HTTP methods are handled by this method. It's up to HandlerAdapters or handlers
 * themselves to decide which methods are acceptable.
 * @param request current HTTP request
 * @param response current HTTP response
 * @throws Exception in case of any kind of processing failure
 */
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 {
		//使用multipartResolver检测request是否为a multipart request;
		//如果是,则解析为 multipart request
			processedRequest = checkMultipart(request);
			multipartRequestParsed = (processedRequest != request);

			// Determine handler for the current request.
			//根据当前请求,或者处理器链 参考⑧ 
			mappedHandler = getHandler(processedRequest);
			if (mappedHandler == null) {
				noHandlerFound(processedRequest, response);
				return;
			}

			// Determine handler adapter for the current request.
			//根据HandlerExecutionChain 的Handler对象,获取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;
				}
			}
//执行HandlerExecutionChain中每个拦截器的preHandle方法
			if (!mappedHandler.applyPreHandle(processedRequest, response)) {
				return;
			}

			// Actually invoke the handler.
			//核心方法!!!获取MAV  参考 (10)
			mv = ha.handle(processedRequest, response, mappedHandler.getHandler());

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

			applyDefaultViewName(processedRequest, mv);
			//执行handlerExecutionChain中拦截器的postHandle()方法
			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);
		}
		//处理器处理结果 参考(11)
		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);
			}
		}
	}
}

⑧DispatcherServlet.getHandler()

@Nullable
	protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
		if (this.handlerMappings != null) {
			for (HandlerMapping hm : this.handlerMappings) {
				if (logger.isTraceEnabled()) {
					logger.trace(
							"Testing handler map [" + hm + "] in DispatcherServlet with name '" + getServletName() + "'");
				}
				//根据hanlerMapping和请求获取HandlerExecutionChain ,参考(8.1)
				HandlerExecutionChain handler = hm.getHandler(request);
				if (handler != null) {
					return handler;
				}
			}
		}
		return null;
	}

(8.1)AbstractHandlerMapping.getHandler()

源码如下:

/**
	 * Look up a handler for the given request, falling back to the default
	 * handler if no specific one is found.
	 * @param request current HTTP request
	 * @return the corresponding handler instance, or the default handler
	 * @see #getHandlerInternal
	 */
	@Override
	@Nullable
	public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
	//获取handler 参考(8.3)
		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 = obtainApplicationContext().getBean(handlerName);
		}
// 根据handler和请求,获取HandlerExecutionChain   参考(8.6)
		HandlerExecutionChain executionChain = getHandlerExecutionChain(handler, request);
		if (CorsUtils.isCorsRequest(request)) {
			CorsConfiguration globalConfig = this.globalCorsConfigSource.getCorsConfiguration(request);
			CorsConfiguration handlerConfig = getCorsConfiguration(handler, request);
			CorsConfiguration config = (globalConfig != null ? globalConfig.combine(handlerConfig) : handlerConfig);
			executionChain = getCorsHandlerExecutionChain(request, executionChain, config);
		}
		return executionChain;
	}

(8.3)AbstractHandlerMethodMapping.getHandlerInternal()

源码如下:

/**
	 * Look up a handler method for the given request.
	 */
	@Override
	protected HandlerMethod getHandlerInternal(HttpServletRequest request) throws Exception {
		//找到请求的url 本例这里为 /login
		String lookupPath = getUrlPathHelper().getLookupPathForRequest(request);
		if (logger.isDebugEnabled()) {
			logger.debug("Looking up handler method for path " + lookupPath);
		}
		//获取mappingRegistry的读锁
		this.mappingRegistry.acquireReadLock();
		try {
			// 查找处理方法 参考(8.4)
			HandlerMethod handlerMethod = lookupHandlerMethod(lookupPath, request);
			if (logger.isDebugEnabled()) {
				if (handlerMethod != null) {
					logger.debug("Returning handler method [" + handlerMethod + "]");
				}
				else {
					logger.debug("Did not find handler method for [" + lookupPath + "]");
				}
			}
			// 这里很有意思  参考8.5
			return (handlerMethod != null ? handlerMethod.createWithResolvedBean() : null);
		}
		finally {
			//释放读锁
			this.mappingRegistry.releaseReadLock();
		}
	}

(8.4)AbstractHandlerMethodMapping.lookupHandlerMethod()

源码如下:

/**
	 * Look up the best-matching handler method for the current request.
	 * If multiple matches are found, the best match is selected.
	 * @param lookupPath mapping lookup path within the current servlet mapping
	 * @param request the current request
	 * @return the best-matching handler method, or {@code null} if no match
	 * @see #handleMatch(Object, String, HttpServletRequest)
	 * @see #handleNoMatch(Set, String, HttpServletRequest)
	 */
	@Nullable
	protected HandlerMethod lookupHandlerMethod(String lookupPath, HttpServletRequest request) throws Exception {
		List<Match> matches = new ArrayList<>();

//A registry that maintains all mappings to handler methods, exposing methods  to perform lookups and providing concurrent access.
// 这里为[{[/login]}]
		List<T> directPathMatches = this.mappingRegistry.getMappingsByUrl(lookupPath);
	
		//如果directPathMatches不为null,就向matches添加
		//matches.add(new Match(match, this.mappingRegistry.getMappings().get(mapping)));
		//match 为RequestMappingInfo 对象
		if (directPathMatches != null) {
			addMatchingMappings(directPathMatches, matches, request);
		}
		if (matches.isEmpty()) {
			// No choice but to go through all mappings...
			addMatchingMappings(this.mappingRegistry.getMappings().keySet(), matches, request);
		}

		if (!matches.isEmpty()) {
			Comparator<Match> comparator = new MatchComparator(getMappingComparator(request));
			//使用工具类进行排序
			Collections.sort(matches, comparator);
			if (logger.isTraceEnabled()) {
				logger.trace("Found " + matches.size() + " matching mapping(s) for [" +
						lookupPath + "] : " + matches);
			}
			//获取排序后的最好的Match对象
			Match bestMatch = matches.get(0);
			if (matches.size() > 1) {
				if (CorsUtils.isPreFlightRequest(request)) {
					return PREFLIGHT_AMBIGUOUS_MATCH;
				}
				//获取第二个最好的Match对象
				Match secondBestMatch = matches.get(1);
				if (comparator.compare(bestMatch, secondBestMatch) == 0) {
					Method m1 = bestMatch.handlerMethod.getMethod();
					Method m2 = secondBestMatch.handlerMethod.getMethod();
					throw new IllegalStateException("Ambiguous handler methods mapped for HTTP path '" +
							request.getRequestURL() + "': {" + m1 + ", " + m2 + "}");
				}
			}
			//Expose URI template variables, matrix variables, and producible media types in the request
			handleMatch(bestMatch.mapping, lookupPath, request);
			//将HandlerMethod对象返回
			return bestMatch.handlerMethod;
		}
		else {
			return handleNoMatch(this.mappingRegistry.getMappings().keySet(), lookupPath, request);
		}
	}

其中matches为一个链表,存放Match对象,每个Match对象由(T)Mapping对象和HandlerMethod对象组成,如下图所示:

8AEFD0DC-A18F-7471-6630-F57A6930537C.jpeg

其中HandlerMethod包含了方法相关的详细信息,如下所示:

ED8BB1DD-37C3-48C4-FDF4-B87455F1F1E0.jpeg

有方法名、URL、返回类型,参数值即方法上面的注解等等!


(8.5)HandlerMethod.createWithResolvedBean()方法

源码如下:

/**
	 * If the provided instance contains a bean name rather than an object instance,
	 * the bean name is resolved before a {@link HandlerMethod} is created and returned.
	 */
	public HandlerMethod createWithResolvedBean() {
		Object handler = this.bean;
		if (this.bean instanceof String) {
			Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
			String beanName = (String) this.bean;
			//根据beanName从工厂里面返回一个bean--本例为LoginController
			handler = this.beanFactory.getBean(beanName);
		}
		// 返回一个新的HandlerMethod对象
		return new HandlerMethod(this, handler);
	}

(8.6)AbstractHandlerMapping.getHandlerExecutionChain()方法

源码如下:

protected HandlerExecutionChain getHandlerExecutionChain(Object handler, HttpServletRequest request) {
		//获取一个HandlerExecutionChain
		HandlerExecutionChain chain = (handler instanceof HandlerExecutionChain ?
				(HandlerExecutionChain) handler : new HandlerExecutionChain(handler));
		//根据请求url,获取匹配的拦截器
		String lookupPath = this.urlPathHelper.getLookupPathForRequest(request);
		for (HandlerInterceptor interceptor : this.adaptedInterceptors) {
			if (interceptor instanceof MappedInterceptor) {
				MappedInterceptor mappedInterceptor = (MappedInterceptor) interceptor;
				if (mappedInterceptor.matches(lookupPath, this.pathMatcher)) {
					//向chain中添加interceptor
					chain.addInterceptor(mappedInterceptor.getInterceptor());
				}
			}
			else {
				chain.addInterceptor(interceptor);
			}
		}
		return chain;
	}

⑨ DispatcherServlet.getHandlerAdapter()方法

源码如下:

/**
* Return the HandlerAdapter for this handler object.
 * @param handler the handler object to find an adapter for
 * @throws ServletException if no HandlerAdapter can be found for the handler. This is a fatal error.
 */
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
	if (this.handlerAdapters != null) {
		//遍历初始化的所有handlerAdapters找到合适的一个并返回
		for (HandlerAdapter ha : this.handlerAdapters) {
			if (logger.isTraceEnabled()) {
				logger.trace("Testing handler adapter [" + ha + "]");
			}
			//判断是否支持 本例这里返回的是RequestMappingHandlerAdapter
			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");
}

(10)AbstractHandlerMethodAdapter.handle()方法

源码如下:

/**
* This implementation expects the handler to be an {@link HandlerMethod}.
 */
@Override
@Nullable
public final ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)
		throws Exception {
//参考 (10.1)
	return handleInternal(request, response, (HandlerMethod) handler);
}

(10.1)RequestMappingHandlerAdapter.handleInternal()方法

源码如下:

@Override
	protected ModelAndView handleInternal(HttpServletRequest request,
			HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

		ModelAndView mav;
		checkRequest(request);

		// 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) {
					mav = invokeHandlerMethod(request, response, handlerMethod);
				}
			}
			else {
				// No HttpSession available -> no mutex necessary
				mav = invokeHandlerMethod(request, response, handlerMethod);
			}
		}
		else {
			// No synchronization on session demanded at all...
			//参考(10.2)
			mav = invokeHandlerMethod(request, response, handlerMethod);
		}

		if (!response.containsHeader(HEADER_CACHE_CONTROL)) {
			if (getSessionAttributesHandler(handlerMethod).hasSessionAttributes()) {
				applyCacheSeconds(response, this.cacheSecondsForSessionAttributeHandlers);
			}
			else {
				prepareResponse(response);
			}
		}

		return mav;
	}

(10.2)RequestMappingHandlerAdapter.invokeHandlerMethod()方法

源码如下:

@Nullable
protected ModelAndView invokeHandlerMethod(HttpServletRequest request,
		HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {

	ServletWebRequest webRequest = new ServletWebRequest(request, response);
	try {
		//数据绑定工厂,本例这里为ServletRequestDataBinderFactory
		WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
		//ModelFactory(attrMethods, binderFactory, sessionAttrHandler)
		ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);

		ServletInvocableHandlerMethod invocableMethod = createInvocableHandlerMethod(handlerMethod);
		//如果参数处理器不为null,则为invocableMethod 设置参数处理器;
		//本例这里参数处理器为HandlerMethodArgumentResolverComposite
		if (this.argumentResolvers != null) {
			invocableMethod.setHandlerMethodArgumentResolvers(this.argumentResolvers);
		}
		//如果返回值处理器不为null,则为invocableMethod 设置返回值处理器
		//本例这里返回值处理器为HandlerMethodReturnValueHandlerComposite
		if (this.returnValueHandlers != null) {
			invocableMethod.setHandlerMethodReturnValueHandlers(this.returnValueHandlers);
		}
		//为invocableMethod设置数据绑定工厂
		invocableMethod.setDataBinderFactory(binderFactory);
		
		//为invocableMethod设置参数名发现器
		//本例这里为DefaultParameterNameDiscoverer
		invocableMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
		
		//创建ModelAndViewContainer 
		ModelAndViewContainer mavContainer = new ModelAndViewContainer();
		mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
/**
Populate the model in the following order: 
1.Retrieve "known" session attributes listed as @SessionAttributes. 
2.Invoke @ModelAttribute methods 
3.Find @ModelAttribute method arguments also listed as @SessionAttributes and ensure they're present in the model raisingan exception if necessary. 
*/
		modelFactory.initModel(webRequest, mavContainer, invocableMethod);
		mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);

		AsyncWebRequest asyncWebRequest = WebAsyncUtils.createAsyncWebRequest(request, response);
		asyncWebRequest.setTimeout(this.asyncRequestTimeout);

		WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
		asyncManager.setTaskExecutor(this.taskExecutor);
		asyncManager.setAsyncWebRequest(asyncWebRequest);
		asyncManager.registerCallableInterceptors(this.callableInterceptors);
		asyncManager.registerDeferredResultInterceptors(this.deferredResultInterceptors);

		if (asyncManager.hasConcurrentResult()) {
			Object result = asyncManager.getConcurrentResult();
			mavContainer = (ModelAndViewContainer) asyncManager.getConcurrentResultContext()[0];
			asyncManager.clearConcurrentResult();
			if (logger.isDebugEnabled()) {
				logger.debug("Found concurrent result value [" + result + "]");
			}
			invocableMethod = invocableMethod.wrapConcurrentResult(result);
		}
//要开始解析参数并处理实际目标方法了  参考(10.3)
		invocableMethod.invokeAndHandle(webRequest, mavContainer);
		if (asyncManager.isConcurrentHandlingStarted()) {
			return null;
		}
//获取ModelAndView并返回,参考(10.7)
		return getModelAndView(mavContainer, modelFactory, webRequest);
	}
	finally {
		webRequest.requestCompleted();
	}
}

(10.3)ServletInvocableHandlerMethod.invokeAndHandle()

源码如下:

public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
//执行目标方法,获取返回值  参考 (10.4)
		Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
		setResponseStatus(webRequest);

//判断返回值是否为null,如果为null mavContainer.setRequestHandled(true);不再进行视图解析
		if (returnValue == null) {
			if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
/*	Whether the request has been handled fully within the handler, e.g. @ResponseBody method, and therefore view resolution is notnecessary. 
This flag can also be set when controller methods declare anargument of type ServletResponse or OutputStream). 
The default value is false.*/
				mavContainer.setRequestHandled(true);
				return;
			}
		}
		else if (StringUtils.hasText(getResponseStatusReason())) {
			mavContainer.setRequestHandled(true);
			return;
		}
//设置为false,说明需要进行视图解析-视图渲染
		mavContainer.setRequestHandled(false);
		//断言
		Assert.state(this.returnValueHandlers != null, "No return value handlers");
		try {
		//使用返回值处理器处理返回值
		//本例这里为HandlerMethodReturnValueHandlerComposite
		//参考(10.5)
			this.returnValueHandlers.handleReturnValue(
					returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
		}
		catch (Exception ex) {
			if (logger.isTraceEnabled()) {
				logger.trace(getReturnValueHandlingErrorMessage("Error handling return value", returnValue), ex);
			}
			throw ex;
		}
	}

(10.4).InvocableHandlerMethod.invokeForRequest()

Invoke the method after resolving its argument values in the context of the given request.Argument values are commonly resolved through {@link HandlerMethodArgumentResolver}s.

源码如下:

public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer,
			Object... providedArgs) throws Exception {
		//获取方法参数
		Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
		if (logger.isTraceEnabled()) {
			logger.trace("Invoking '" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
					"' with arguments " + Arrays.toString(args));
		}
		//执行实际目标方法,并获取返回值
//本例这里获取的返回值:ModelAndView: reference to view with name 'login'; model is null
		Object returnValue = doInvoke(args);
		if (logger.isTraceEnabled()) {
			logger.trace("Method [" + ClassUtils.getQualifiedMethodName(getMethod(), getBeanType()) +
					"] returned [" + returnValue + "]");
		}
		return returnValue;
	}

(10.5)HandlerMethodReturnValueHandlerComposite.handleReturnValue()

源码如下:

public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
		//获取返回值处理器,本例这里为ModelAndViewMethodReturnValueHandler
		HandlerMethodReturnValueHandler handler = selectHandler(returnValue, returnType);
		if (handler == null) {
			throw new IllegalArgumentException("Unknown return value type: " + returnType.getParameterType().getName());
		}
		//返回值处理,参考(10.6)
		handler.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
	}

(10.6).ModelAndViewMethodReturnValueHandler.handleReturnValue()

源码如下:

@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
		
		//如果返回值为null 直接返回
		if (returnValue == null) {
			mavContainer.setRequestHandled(true);
			return;
		}
		//将返回值对象强转为ModelAndView 
		ModelAndView mav = (ModelAndView) returnValue;

		//Return whether we use a view reference, i.e. true if the view has been specified via a 
		//name to be resolved by the DispatcherServlet via a ViewResolver.
		if (mav.isReference()) {
			//获取视图名,本例这里为"login"
			String viewName = mav.getViewName();
			mavContainer.setViewName(viewName);
			//是否重定向
			if (viewName != null && isRedirectViewName(viewName)) {
				mavContainer.setRedirectModelScenario(true);
			}
		}
		else {
			View view = mav.getView();
			mavContainer.setView(view);
			if (view instanceof SmartView) {
				if (((SmartView) view).isRedirectView()) {
					mavContainer.setRedirectModelScenario(true);
				}
			}
		}
		mavContainer.setStatus(mav.getStatus());
		//返回值对象里面的model放到mavContainer
		mavContainer.addAllAttributes(mav.getModel());
	}

(10.7)RequestMappingHandlerAdapter.getModelAndView()

源码如下:

private ModelAndView getModelAndView(ModelAndViewContainer mavContainer,
			ModelFactory modelFactory, NativeWebRequest webRequest) throws Exception {
//Promote model attributes listed as {@code @SessionAttributes} to the session.
// Add {@link BindingResult} attributes where necessary.
		modelFactory.updateModel(webRequest, mavContainer);
		if (mavContainer.isRequestHandled()) {
			return null;
		}
		ModelMap model = mavContainer.getModel();
		ModelAndView mav = new ModelAndView(mavContainer.getViewName(), model, mavContainer.getStatus());
		if (!mavContainer.isViewReference()) {
			mav.setView((View) mavContainer.getView());
		}
		if (model instanceof RedirectAttributes) {
			Map<String, ?> flashAttributes = ((RedirectAttributes) model).getFlashAttributes();
			HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class);
			if (request != null) {
				RequestContextUtils.getOutputFlashMap(request).putAll(flashAttributes);
			}
		}
		return mav;
	}

(11)DispatcherServlet.processDispatchResult()

源码如下:

private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
			@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
			@Nullable Exception exception) throws Exception {

		boolean errorView = false;

		if (exception != null) {
			if (exception instanceof ModelAndViewDefiningException) {
				logger.debug("ModelAndViewDefiningException encountered", exception);
				mv = ((ModelAndViewDefiningException) exception).getModelAndView();
			}
			else {
				Object handler = (mappedHandler != null ? mappedHandler.getHandler() : null);
				mv = processHandlerException(request, response, handler, exception);
				errorView = (mv != null);
			}
		}

		// Did the handler return a view to render?
		if (mv != null && !mv.wasCleared()) {
		// 渲染视图!!!参考(12)
			render(mv, request, response);
			if (errorView) {
				WebUtils.clearErrorRequestAttributes(request);
			}
		}
		else {
			if (logger.isDebugEnabled()) {
				logger.debug("Null ModelAndView returned to DispatcherServlet with name '" + getServletName() +
						"': assuming HandlerAdapter completed request handling");
			}
		}

		if (WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
			// Concurrent handling started during a forward
			return;
		}

		if (mappedHandler != null) {
		//执行拦截器的afterCompletion方法  参考(13)
			mappedHandler.triggerAfterCompletion(request, response, null);
		}
	}

(12).DispatcherServlet.render()

源码如下:

protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
		// Determine locale for request and apply it to the response.
		//本例这里为zh_CN
		Locale locale =
				(this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale());
		//为响应设置Locale对象
		response.setLocale(locale);

		View view;
		String viewName = mv.getViewName();
		if (viewName != null) {
			// We need to resolve the view name.
			//根据视图解析器获取View对象
			view = resolveViewName(viewName, mv.getModelInternal(), locale, request);
			if (view == null) {
				throw new ServletException("Could not resolve view with name '" + mv.getViewName() +
						"' in servlet with name '" + getServletName() + "'");
			}
		}
		else {
			// No need to lookup: the ModelAndView object contains the actual View object.
			view = mv.getView();
			if (view == null) {
				throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a " +
						"View object in servlet with name '" + getServletName() + "'");
			}
		}

		// Delegate to the View object for rendering.
		if (logger.isDebugEnabled()) {
			logger.debug("Rendering view [" + view + "] in DispatcherServlet with name '" + getServletName() + "'");
		}
		try {
			if (mv.getStatus() != null) {
				response.setStatus(mv.getStatus().value());
			}
/*Render the view given the specified model. 
The first step will be preparing the request: In the JSP case,this would mean setting model objects as request attributes.
The second step will be the actual rendering of the view,for example including the JSP via a RequestDispatcher.
*/
			view.render(mv.getModelInternal(), request, response);
		}
		catch (Exception ex) {
			if (logger.isDebugEnabled()) {
				logger.debug("Error rendering view [" + view + "] in DispatcherServlet with name '" +
						getServletName() + "'", ex);
			}
			throw ex;
		}
	}

(13)HandlerExecutionChain.triggerAfterCompletion

源码如下:

void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex)
			throws Exception {

		HandlerInterceptor[] interceptors = getInterceptors();
		if (!ObjectUtils.isEmpty(interceptors)) {
			for (int i = this.interceptorIndex; i >= 0; i--) {
				HandlerInterceptor interceptor = interceptors[i];
				try {
					interceptor.afterCompletion(request, response, this.handler, ex);
				}
				catch (Throwable ex2) {
					logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
				}
			}
		}
	}

程序依次返回,直到第⑤中的publishRequestHandledEvent!


(14)FrameworkServlet.publishRequestHandledEvent

源码如下:

private void publishRequestHandledEvent(HttpServletRequest request, HttpServletResponse response,
			long startTime, @Nullable Throwable failureCause) {

		if (this.publishEvents && this.webApplicationContext != null) {
			// Whether or not we succeeded, publish an event.
			long processingTime = System.currentTimeMillis() - startTime;
			this.webApplicationContext.publishEvent(
					new ServletRequestHandledEvent(this,
							request.getRequestURI(), request.getRemoteAddr(),
							request.getMethod(), getServletConfig().getServletName(),
							WebUtils.getSessionId(request), getUsernameForRequest(request),
							processingTime, failureCause, response.getStatus()));
		}
	}

其调用了webApplicationContext.publishEvent!是不是很熟悉?


【5】@ResponseBody注解返回JSON

即,方法返回json,不再是视图,此时该如何?

此时(10.5)中改变RequestResponseBodyMethodProcessor.handleReturnValue():

@Override
	public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
			ModelAndViewContainer mavContainer, NativeWebRequest webRequest)
			throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {

		mavContainer.setRequestHandled(true);
		ServletServerHttpRequest inputMessage = createInputMessage(webRequest);
		ServletServerHttpResponse outputMessage = createOutputMessage(webRequest);

		// Try even with null return value. ResponseBodyAdvice could get involved.
		writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage);
	}

【6】SpringBoot下容器是怎样的?

① SpringMVC容器创建流程的不同

这里在FrameworkServlet.initServletBean()中打了断点,如下图所示:

17317D69-2D24-780F-15A8-6FD18FB562D3.png

首先进入initServletBean()方法,然后进入initWebApplicationContext()方法:

EF43E21A-A9D5-27C5-5DF6-4ECD3012EB50.png

然后并不会走一系列创建、初始化、配置等方法,而是直接跳了过去:

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

		if (this.webApplicationContext != null) {
			// A context instance was injected at construction time -> use it
			//SpringBoot下wac-->this.webApplicationContext-->rootContext 
			wac = this.webApplicationContext;
			if (wac instanceof ConfigurableWebApplicationContext) {
				ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
				//因为rootContext isActive,所以下面方法不会再执行
				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) {
			// No context instance was injected at construction time -> see if one
			// has been registered in the servlet context. If one exists, it is assumed
			// that the parent context (if any) has already been set and that the
			// user has performed any initialization such as setting the context id
			wac = findWebApplicationContext();
		}
		if (wac == null) {
			// No context instance is defined for this servlet -> create a local one
			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.
			synchronized (this.onRefreshMonitor) {
				onRefresh(wac);
			}
		}
//将DispatcherServlet容器发布到ServletContext中
//其实还是RootContext容器,但是attrName为org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcherServlet
		if (this.publishContext) {
			// Publish the context as a servlet context attribute.
			String attrName = getServletContextAttributeName();
			getServletContext().setAttribute(attrName, wac);
		}

		return wac;
	}

857F36C0-F015-00B9-FED0-83A2FBD81ADD.png

90DD8878-1F2C-148B-C421-DFD1D80353A2.png

与普通Web环境中这点大不一样!为什么?继续分析。还看FrameworkServlet.initWebApplicationContext()方法,注意图中箭头标注的注释。

584B9DF1-494F-CA40-199B-D26666E4388A.png

然后再看一下当前FrameworkServlet对象:

6CB370CD-D10B-3ACF-916F-E3056B4EF4E7.png

该值默认为false,setApplicationContext方法中设置为true:

/** If the WebApplicationContext was injected via {@link #setApplicationContext}. */
private boolean webApplicationContextInjected = false;

/**
* Called by Spring via {@link ApplicationContextAware} to inject the current
* application context. This method allows FrameworkServlets to be registered as
* Spring beans inside an existing {@link WebApplicationContext} rather than
* {@link #findWebApplicationContext() finding} a
* {@link org.springframework.web.context.ContextLoaderListener bootstrapped} context.
* <p>Primarily added to support use in embedded servlet containers.
* @since 4.0
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
	if (this.webApplicationContext == null && applicationContext instanceof WebApplicationContext) {
		this.webApplicationContext = (WebApplicationContext) applicationContext;
		this.webApplicationContextInjected = true;
	}
}

也就是说在setApplicationContext中已经为当前对象的webApplicationContext属性赋值,并将webApplicationContextInjected设置为true。故而在FrameworkServlet.initWebApplicationContext()中不会再走一系列创建、初始化、配置等方法,而是直接跳了过去!


在setApplicationContext中打上断点,重启应用,如下所示:

FDC8291A-1AB2-6B08-1C7B-DDA2E223071D.png

DispatcherServlet.onRefresh方法:

onRefresh方法将会调用initStrategies(context);方法,后者是初始化一系列SpringMVC需要的对象。

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

initStrategies方法:

protected void initStrategies(ApplicationContext context) {
		initMultipartResolver(context);
		initLocaleResolver(context);
		initThemeResolver(context);
		initHandlerMappings(context);
		initHandlerAdapters(context);
		initHandlerExceptionResolvers(context);
		initRequestToViewNameTranslator(context);
		initViewResolvers(context);
		initFlashMapManager(context);
	}

把DispatcherServlet容器发布到ServletContext中

如下图所示,这里以org.springframework.web.servlet.FrameworkServlet.CONTEXT.dispatcherServlet为键,wac为value放到ServletContext(ApplicationContextFacade)中:

931A16FA-1CB3-C476-1495-FBB6B8C132AE.png

总结:在Web环境中是由Spring和SpringMvc两个容器组成的,在SpringBoot环境中只有一个容器RootContext。


还有一个问题,Spring容器或者说SpringBoot中根容器(除去Tomcat的容器外)在哪里创建和初始化?

参考博文:SpringBoot配置外部Tomcat项目启动流程源码分析(长文)

收藏 (0)
评论列表
正在载入评论列表...
我是有底线的
为您推荐
    暂时没有数据