首页 > 编程语言 >SpringMVC源码-DispatcherServlet初始化

SpringMVC源码-DispatcherServlet初始化

时间:2022-10-30 12:37:11浏览次数:51  
标签:ApplicationContext null SpringMVC wac 源码 context logger DispatcherServlet servle

web容器启动后会实例化Servlet,会执行Servlet的init方法且只会执行一次。后续调用doService处理客户请求。

DispatcherServlet的构造方法

public DispatcherServlet() {
	super();
	setDispatchOptionsRequest(true);
}

调用了父类的构造方法,设置dispatchOptionsRequest属性为true。

HttpServletBean.init()

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

1、ServletConfigPropertyValues从ServletConfig获取属性值并添加到ServletConfigPropertyValues对象中,同时检查必须的属性值
2、若从第一步获取的属性值PropertyValues非空,调用PropertyAccessorFactory.forBeanPropertyAccess将DispatcherServlet封装成BeanWrapper,BeanWrapper注册Resource自定义属性编辑器ResourceEditor,调用initBeanWrapper初始化BeanWrapper,将从第一步获取的属性值PropertyValues设置到BeanWrapper
3、initServletBean

ServletConfigPropertyValues

public ServletConfigPropertyValues(ServletConfig config, Set<String> requiredProperties)
			throws ServletException {

		Set<String> missingProps = (!CollectionUtils.isEmpty(requiredProperties) ?
				new HashSet<>(requiredProperties) : null);

		Enumeration<String> paramNames = config.getInitParameterNames();
		while (paramNames.hasMoreElements()) {
			String property = paramNames.nextElement();
			Object value = config.getInitParameter(property);
			addPropertyValue(new PropertyValue(property, value));
			if (missingProps != null) {
				missingProps.remove(property);
			}
		}

		// Fail if we are still missing properties.
		if (!CollectionUtils.isEmpty(missingProps)) {
			throw new ServletException(
					"Initialization from ServletConfig for servlet '" + config.getServletName() +
					"' failed; the following required properties were missing: " +
					StringUtils.collectionToDelimitedString(missingProps, ", "));
		}
	}

1、由requiredProperties属性List构造出missingProps集合
2、从ServletConfig获取初始参数名列表
3、遍历第二步的集合,从ServletConfig获取属性值并添加到PropertyValue,同时将该属性从missingProps中移除
4.若missingProps不为空,即ServletConfig缺失必须的属性值则抛出异常

FrameworkServlet.initServletBean()

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

1、initWebApplicationContext初始化WebApplicationContext
2、initFrameworkServlet(空方法)

FrameworkServlet.initWebApplicationContext()

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

	if (this.publishContext) {
		// Publish the context as a servlet context attribute.
		String attrName = getServletContextAttributeName();
		getServletContext().setAttribute(attrName, wac);
	}

	return wac;
}

1、WebApplicationContextUtils.getWebApplicationContext通过WebApplicationContext.class.getName() + ".ROOT"名从ServletContext中获取属性值,即ContextLoaderListener在初始化上下文时创建的Spring WebApplicationContext上下文对象
2、判断当前上下文webApplicationContext是否非空,且是ConfigurableWebApplicationContext类型,且未活动则设置父上下文为从第一部获取的WebApplicationContext,调用configureAndRefreshWebApplicationContext配置和刷新上下文
3、如果当前上下文为空findWebApplicationContext获取当前上下文
4、如果当前上下文为空createWebApplicationContext创建当前上下文
5、refreshEventReceived为false,调用onRefresh
6、publishContext为true,FrameworkServlet.class.getName() + ".CONTEXT."+getServletName()为key,当前上下文为value设置到ServletContext

FrameworkServlet.findWebApplicationContext()

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

1、getContextAttribute获取属性值,默认为null
2、若第一步的属性值为null,直接返回null
3、否则WebApplicationContextUtils.getWebApplicationContext从ServletContext获取上下文,若获取不到抛出异常,获取到了返回

FrameworkServlet.createWebApplicationContext(@Nullable WebApplicationContext parent)

protected WebApplicationContext createWebApplicationContext(@Nullable WebApplicationContext parent) {
	return createWebApplicationContext((ApplicationContext) parent);
}

FrameworkServlet.createWebApplicationContext(@Nullable ApplicationContext parent)

	protected WebApplicationContext createWebApplicationContext(@Nullable ApplicationContext parent) {
	Class<?> contextClass = getContextClass();
	if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
		throw new ApplicationContextException(
				"Fatal initialization error in servlet with name '" + getServletName() +
				"': custom WebApplicationContext class [" + contextClass.getName() +
				"] is not of type ConfigurableWebApplicationContext");
	}
	ConfigurableWebApplicationContext wac =
			(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);

	wac.setEnvironment(getEnvironment());
	wac.setParent(parent);
	String configLocation = getContextConfigLocation();
	if (configLocation != null) {
		wac.setConfigLocation(configLocation);
	}
	configureAndRefreshWebApplicationContext(wac);

	return wac;
}

1、getContextClass获取contextClass,是XmlWebApplicationContext类型

private Class<?> contextClass = DEFAULT_CONTEXT_CLASS;
public static final Class<?> DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;

2、BeanUtils.instantiateClass实例化contextClass为ConfigurableWebApplicationContext
3、ConfigurableWebApplicationContext设置Environment和父上下文parent
4、getContextConfigLocation获取contextConfigLocation,即web.xml中servlet下配置init-param参数:

<servlet>
	<servlet-name>dispatcherServlet</servlet-name>
	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	<init-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>classpath:mvc.xml</param-value>
	</init-param>
	<load-on-startup>1</load-on-startup>
	<async-supported>true</async-supported>
</servlet>

5、configureAndRefreshWebApplicationContext配置和刷新ConfigurableWebApplicationContext
6、返回

FrameworkServlet.configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac)

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

	wac.setServletContext(getServletContext());
	wac.setServletConfig(getServletConfig());
	wac.setNamespace(getNamespace());
	wac.addApplicationListener(new SourceFilteringListener(wac, new ContextRefreshListener()));

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

	postProcessWebApplicationContext(wac);
	applyInitializers(wac);
	wac.refresh();
}

1、ConfigurableWebApplicationContext设置id
2、ConfigurableWebApplicationContext设置ServletContext和ServletConfig,设置Namespace
3、添加ApplicationListener监听器ContextRefreshListener
4、获取Environment并调用initPropertySources替换servletContextInitParams和servletConfigInitParams参数
5、postProcessWebApplicationContext
6、applyInitializers在ConfigurableWebApplicationContext刷新之前将globalInitializerClasses参数解析成ApplicationContextInitializer并调用ApplicationContextInitializer.initialize
7、刷新容器,对mvc.xml文件解析成BeanDifinition,创建bean,在下篇文章进行。

ContextRefreshListener

private class ContextRefreshListener implements ApplicationListener<ContextRefreshedEvent> {

	@Override
	public void onApplicationEvent(ContextRefreshedEvent event) {
		FrameworkServlet.this.onApplicationEvent(event);
	}
}

ContextRefreshListener监听ContextRefreshedEvent事件,当ContextRefreshedEvent事件发生时,执行onApplicationEvent。上面调用refresh()方法时,会发布ContextRefreshedEvent事件。

FrameworkServlet.onApplicationEvent(ContextRefreshedEvent event)

public void onApplicationEvent(ContextRefreshedEvent event) {
	this.refreshEventReceived = true;
	synchronized (this.onRefreshMonitor) {
		onRefresh(event.getApplicationContext());
	}
}

1、设置refreshEventReceived为true

private volatile boolean refreshEventReceived;

2、执行onRefresh

onRefresh(ApplicationContext context)

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

initStrategies(ApplicationContext context)

	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处理请求所需的组件。这些组件的创建和解析是通过mvc.xml文件配置实现的,主要是mvc:annotation-driven/

DispatcherServlet.initMultipartResolver(ApplicationContext context)

private void initMultipartResolver(ApplicationContext context) {
	try {
		this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
		if (logger.isTraceEnabled()) {
			logger.trace("Detected " + this.multipartResolver);
		}
		else if (logger.isDebugEnabled()) {
			logger.debug("Detected " + this.multipartResolver.getClass().getSimpleName());
		}
	}
	catch (NoSuchBeanDefinitionException ex) {
		// Default is no multipart resolver.
		this.multipartResolver = null;
		if (logger.isTraceEnabled()) {
			logger.trace("No MultipartResolver '" + MULTIPART_RESOLVER_BEAN_NAME + "' declared");
		}
	}
}

从ApplicationContext中获取所有类型为MultipartResolver的bean并且设置到multipartResolver。出现异常调用getDefaultStrategies获取MultipartResolver。MultipartResolver用于上传文件处理。

DispatcherServlet.initLocaleResolver(ApplicationContext context)

	private void initLocaleResolver(ApplicationContext context) {
	try {
		this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
		if (logger.isTraceEnabled()) {
			logger.trace("Detected " + this.localeResolver);
		}
		else if (logger.isDebugEnabled()) {
			logger.debug("Detected " + this.localeResolver.getClass().getSimpleName());
		}
	}
	catch (NoSuchBeanDefinitionException ex) {
		// We need to use the default.
		this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
		if (logger.isTraceEnabled()) {
			logger.trace("No LocaleResolver '" + LOCALE_RESOLVER_BEAN_NAME +
					"': using default [" + this.localeResolver.getClass().getSimpleName() + "]");
		}
	}
}

从ApplicationContext中获取所有类型为LocaleResolver的bean并且设置到localeResolver。出现异常调用getDefaultStrategies获取LocaleResolver。LocaleResolver用于处理国际化和不同区域的语言。

DispatcherServlet.initThemeResolver(ApplicationContext context)

private void initThemeResolver(ApplicationContext context) {
	try {
		this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
		if (logger.isTraceEnabled()) {
			logger.trace("Detected " + this.themeResolver);
		}
		else if (logger.isDebugEnabled()) {
			logger.debug("Detected " + this.themeResolver.getClass().getSimpleName());
		}
	}
	catch (NoSuchBeanDefinitionException ex) {
		// We need to use the default.
		this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);
		if (logger.isTraceEnabled()) {
			logger.trace("No ThemeResolver '" + THEME_RESOLVER_BEAN_NAME +
					"': using default [" + this.themeResolver.getClass().getSimpleName() + "]");
		}
	}
}

从ApplicationContext中获取所有类型为ThemeResolver的bean并且设置到themeResolver。出现异常调用getDefaultStrategies获取ThemeResolver。ThemeResolver用于解析主题。

DispatcherServlet.initHandlerMappings(ApplicationContext context)

	private void initHandlerMappings(ApplicationContext context) {
	this.handlerMappings = null;

	if (this.detectAllHandlerMappings) {
		// Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
		Map<String, HandlerMapping> matchingBeans =
				BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
		if (!matchingBeans.isEmpty()) {
			this.handlerMappings = new ArrayList<>(matchingBeans.values());
			// We keep HandlerMappings in sorted order.
			AnnotationAwareOrderComparator.sort(this.handlerMappings);
		}
	}
	else {
		try {
			HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
			this.handlerMappings = Collections.singletonList(hm);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Ignore, we'll add a default HandlerMapping later.
		}
	}

	// Ensure we have at least one HandlerMapping, by registering
	// a default HandlerMapping if no other mappings are found.
	if (this.handlerMappings == null) {
		this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
		if (logger.isTraceEnabled()) {
			logger.trace("No HandlerMappings declared for servlet '" + getServletName() +
					"': using default strategies from DispatcherServlet.properties");
		}
	}

	for (HandlerMapping mapping : this.handlerMappings) {
		if (mapping.usesPathPatterns()) {
			this.parseRequestPath = true;
			break;
		}
	}
}

1、如果detectAllHandlerMappings为true,表示获取所有的HandlerMapping类型的bean,调用BeanFactoryUtils.beansOfTypeIncludingAncestors从ApplicationContext中获取所有类型为HandlerMapping(父类)的bean且按照Order接口排序。否则从ApplicationContext中获取所有类型为HandlerMapping的bean并且设置到handlerMappings。
2、如果handlerMappings为null,调用getDefaultStrategies获取HandlerMapping
3、遍历handlerMappings,如果又HandlerMapping.usesPathPatterns()为true,表示自动使用路径匹配。则设置parseRequestPath为true,退出循环。
HandlerMapping用于将requests映射成处理器。

DispatcherServlet.initHandlerAdapters(ApplicationContext context)

private void initHandlerAdapters(ApplicationContext context) {
	this.handlerAdapters = null;

	if (this.detectAllHandlerAdapters) {
		// Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
		Map<String, HandlerAdapter> matchingBeans =
				BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
		if (!matchingBeans.isEmpty()) {
			this.handlerAdapters = new ArrayList<>(matchingBeans.values());
			// We keep HandlerAdapters in sorted order.
			AnnotationAwareOrderComparator.sort(this.handlerAdapters);
		}
	}
	else {
		try {
			HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
			this.handlerAdapters = Collections.singletonList(ha);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Ignore, we'll add a default HandlerAdapter later.
		}
	}

	// Ensure we have at least some HandlerAdapters, by registering
	// default HandlerAdapters if no other adapters are found.
	if (this.handlerAdapters == null) {
		this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
		if (logger.isTraceEnabled()) {
			logger.trace("No HandlerAdapters declared for servlet '" + getServletName() +
					"': using default strategies from DispatcherServlet.properties");
		}
	}
}

1、如果detectAllHandlerAdapters为true,表示获取所有的HandlerAdapter类型的bean,调用BeanFactoryUtils.beansOfTypeIncludingAncestors从ApplicationContext中获取所有类型为HandlerAdapter(父类)的bean且按照Order接口排序。否则从ApplicationContext中获取所有类型为HandlerAdapter的bean并且设置到handlerAdapters。
2、如果handlerAdapters为null,调用getDefaultStrategies获取HandlerAdapter
HandlerAdapter是MVC框架SPI,允许核心MVC工作流的参数化。

DispatcherServlet.initHandlerExceptionResolvers(ApplicationContext context)

private void initHandlerExceptionResolvers(ApplicationContext context) {
	this.handlerExceptionResolvers = null;

	if (this.detectAllHandlerExceptionResolvers) {
		// Find all HandlerExceptionResolvers in the ApplicationContext, including ancestor contexts.
		Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
				.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
		if (!matchingBeans.isEmpty()) {
			this.handlerExceptionResolvers = new ArrayList<>(matchingBeans.values());
			// We keep HandlerExceptionResolvers in sorted order.
			AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
		}
	}
	else {
		try {
			HandlerExceptionResolver her =
					context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
			this.handlerExceptionResolvers = Collections.singletonList(her);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Ignore, no HandlerExceptionResolver is fine too.
		}
	}

	// Ensure we have at least some HandlerExceptionResolvers, by registering
	// default HandlerExceptionResolvers if no other resolvers are found.
	if (this.handlerExceptionResolvers == null) {
		this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
		if (logger.isTraceEnabled()) {
			logger.trace("No HandlerExceptionResolvers declared in servlet '" + getServletName() +
					"': using default strategies from DispatcherServlet.properties");
		}
	}
}

1、如果detectAllHandlerExceptionResolvers为true,表示获取所有的HandlerExceptionResolver类型的bean,调用BeanFactoryUtils.beansOfTypeIncludingAncestors从ApplicationContext中获取所有类型为HandlerExceptionResolver(父类)的bean且按照Order接口排序。否则从ApplicationContext中获取所有类型为HandlerExceptionResolver的bean并且设置到handlerExceptionResolvers。
2、如果handlerExceptionResolvers为null,调用getDefaultStrategies获取HandlerExceptionResolver
HandlerExceptionResolver处理执行请求出现的异常,通常映射成错误视图。

DispatcherServlet.initRequestToViewNameTranslator(ApplicationContext context)

private void initRequestToViewNameTranslator(ApplicationContext context) {
	try {
		this.viewNameTranslator =
				context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
		if (logger.isTraceEnabled()) {
			logger.trace("Detected " + this.viewNameTranslator.getClass().getSimpleName());
		}
		else if (logger.isDebugEnabled()) {
			logger.debug("Detected " + this.viewNameTranslator);
		}
	}
	catch (NoSuchBeanDefinitionException ex) {
		// We need to use the default.
		this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
		if (logger.isTraceEnabled()) {
			logger.trace("No RequestToViewNameTranslator '" + REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME +
					"': using default [" + this.viewNameTranslator.getClass().getSimpleName() + "]");
		}
	}
}

从ApplicationContext中获取所有类型为RequestToViewNameTranslator的bean并且设置到viewNameTranslator。出现异常调用getDefaultStrategies获取RequestToViewNameTranslator。ThemeResolver用于没有显示提供视图名时将request映射成视图名。

DispatcherServlet.initViewResolvers(ApplicationContext context)

private void initViewResolvers(ApplicationContext context) {
	this.viewResolvers = null;

	if (this.detectAllViewResolvers) {
		// Find all ViewResolvers in the ApplicationContext, including ancestor contexts.
		Map<String, ViewResolver> matchingBeans =
				BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
		if (!matchingBeans.isEmpty()) {
			this.viewResolvers = new ArrayList<>(matchingBeans.values());
			// We keep ViewResolvers in sorted order.
			AnnotationAwareOrderComparator.sort(this.viewResolvers);
		}
	}
	else {
		try {
			ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
			this.viewResolvers = Collections.singletonList(vr);
		}
		catch (NoSuchBeanDefinitionException ex) {
			// Ignore, we'll add a default ViewResolver later.
		}
	}

	// Ensure we have at least one ViewResolver, by registering
	// a default ViewResolver if no other resolvers are found.
	if (this.viewResolvers == null) {
		this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
		if (logger.isTraceEnabled()) {
			logger.trace("No ViewResolvers declared for servlet '" + getServletName() +
					"': using default strategies from DispatcherServlet.properties");
		}
	}
}

1、如果detectAllViewResolvers为true,表示获取所有的ViewResolver类型的bean,调用BeanFactoryUtils.beansOfTypeIncludingAncestors从ApplicationContext中获取所有类型为ViewResolver(父类)的bean且按照Order接口排序。否则从ApplicationContext中获取所有类型为ViewResolver的bean并且设置到viewResolvers。
2、如果viewResolvers为null,调用getDefaultStrategies获取ViewResolver
ViewResolver是视图解析器,用于将视图名解析成视图。

DispatcherServlet.initFlashMapManager(ApplicationContext context)

private void initFlashMapManager(ApplicationContext context) {
	try {
		this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);
		if (logger.isTraceEnabled()) {
			logger.trace("Detected " + this.flashMapManager.getClass().getSimpleName());
		}
		else if (logger.isDebugEnabled()) {
			logger.debug("Detected " + this.flashMapManager);
		}
	}
	catch (NoSuchBeanDefinitionException ex) {
		// We need to use the default.
		this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);
		if (logger.isTraceEnabled()) {
			logger.trace("No FlashMapManager '" + FLASH_MAP_MANAGER_BEAN_NAME +
					"': using default [" + this.flashMapManager.getClass().getSimpleName() + "]");
		}
	}
}

从ApplicationContext中获取所有类型为FlashMapManager的bean并且设置到flashMapManager。出现异常调用getDefaultStrategies获取FlashMapManager。FlashMapManager用于用于检索和保存FlashMap实例。

DispatcherServlet.getDefaultStrategy(ApplicationContext context, Class strategyInterface)

protected <T> T getDefaultStrategy(ApplicationContext context, Class<T> strategyInterface) {
	List<T> strategies = getDefaultStrategies(context, strategyInterface);
	if (strategies.size() != 1) {
		throw new BeanInitializationException(
				"DispatcherServlet needs exactly 1 strategy for interface [" + strategyInterface.getName() + "]");
	}
	return strategies.get(0);
}

DispatcherServlet.getDefaultStrategies(ApplicationContext context, Class strategyInterface)

protected <T> List<T> getDefaultStrategies(ApplicationContext context, Class<T> strategyInterface) {
	if (defaultStrategies == null) {
		try {
			// Load default strategy implementations from properties file.
			// This is currently strictly internal and not meant to be customized
			// by application developers.
			ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class); // 	private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
			defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
		}
		catch (IOException ex) {
			throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage());
		}
	}

	String key = strategyInterface.getName();
	String value = defaultStrategies.getProperty(key);
	if (value != null) {
		String[] classNames = StringUtils.commaDelimitedListToStringArray(value);
		List<T> strategies = new ArrayList<>(classNames.length);
		for (String className : classNames) {
			try {
				Class<?> clazz = ClassUtils.forName(className, DispatcherServlet.class.getClassLoader());
				Object strategy = createDefaultStrategy(context, clazz);
				strategies.add((T) strategy);
			}
			catch (ClassNotFoundException ex) {
				throw new BeanInitializationException(
						"Could not find DispatcherServlet's default strategy class [" + className +
						"] for interface [" + key + "]", ex);
			}
			catch (LinkageError err) {
				throw new BeanInitializationException(
						"Unresolvable class definition for DispatcherServlet's default strategy class [" +
						className + "] for interface [" + key + "]", err);
			}
		}
		return strategies;
	}
	else {
		return Collections.emptyList();
	}
}

1、如果defaultStrategies为null,加载类路径下DispatcherServlet.properties文件,如webmvc项目下resources/org/springframework/web/servlet/DispatcherServlet.properties
2、defaultStrategies获取strategyInterface.getName()为key的值value
3、如果value不为null,按照,分割后遍历调用ClassUtils.forName构建Class,调用createDefaultStrategy创建bean并加到strategies List中返回

webmvc项目下resources/org/springframework/web/servlet/DispatcherServlet.properties

# Default implementation classes for DispatcherServlet's strategy interfaces.
# Used as fallback when no matching beans are found in the DispatcherServlet context.
# Not meant to be customized by application developers.

org.springframework.web.servlet.LocaleResolver=org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver

org.springframework.web.servlet.ThemeResolver=org.springframework.web.servlet.theme.FixedThemeResolver

org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\
	org.springframework.web.servlet.function.support.RouterFunctionMapping

org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
	org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
	org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\
	org.springframework.web.servlet.function.support.HandlerFunctionAdapter


org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\
	org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\
	org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver

org.springframework.web.servlet.RequestToViewNameTranslator=org.springframework.web.servlet.view.DefaultRequestToViewNameTranslator

org.springframework.web.servlet.ViewResolver=org.springframework.web.servlet.view.InternalResourceViewResolver

org.springframework.web.servlet.FlashMapManager=org.springframework.web.servlet.support.SessionFlashMapManager

标签:ApplicationContext,null,SpringMVC,wac,源码,context,logger,DispatcherServlet,servle
From: https://www.cnblogs.com/shigongp/p/16840580.html

相关文章

  • redisson分布式限流[RRateLimiter]源码分析
    接下来在讲一讲平时用的比较多的限流模块--RRateLimiter1.简单使用publicstaticvoidmain(String[]args)throwsInterruptedException{RRateLimiterrateLimit......
  • 多语言在线客服系统源码-自动识别中英环境-私有化部署完美支持跨境电商网站
    如果您的客户遍布全球,客户沟通就必须跨越语言障碍。用客户当地的语言跟他们交谈,可以帮助您在客户生命周期的所有阶段建立信任,当然也包括服务支持。 具体做法,看看这四点......
  • Nginx源码编译并运行
    获取源码包并解压登录http://nginx.org/en/download.htmlwgethttp://nginx.org/download/nginx-1.20.2.tar.gztar-zxvfnginx-1.20.2.tar.gz安装Nginxcdnginx-1.2......
  • spdlog日志库源码:logger类
    目录特性类图关系logger数据成员logger函数成员构造与析构构造函数拷贝构造、移动构造交换操作log()记录日志消息格式串普通字符串日志级别宽字符支持sink_it_:将log消息交......
  • 最新php多商户多仓库带扫描云进销存系统ERP管理系统Saas营销版无限商户源码
    1、电脑端+手机端,手机实时共享,手机端一目了然。2、多商户Saas营销版无限开商户,用户前端自行注册,后台管理员审核开通3、管理员开通商户,可以设置商户到期时间、权限等等,无......
  • Spring源码-SpringMVC-搭建springmvc环境
    一、新建模块myself-web新建gradle的web项目,右键项目名,选择NEW-Moudle.左边选择Gradle,右下选择web即可。build.gradleplugins{id'java'id'war'id"com.bmuschko......
  • xxl-job 源码初探
    xxl-job客户端把JobHandle的value和method映射关系存储到map中1.1启动入口1.2在该文件getBean后被调用1.3xxl-job实际映射位置1.4放置到map中......
  • SpringMVC_day02
    SpringMVC_day02今日内容完成SSM的整合开发能够理解并实现统一结果封装与统一异常处理能够完成前后台功能整合开发掌握拦截器的编写1,SSM整合前面我们已经把Myba......
  • SpringMVC_day01
    SpringMVC_day01今日内容理解SpringMVC相关概念完成SpringMVC的入门案例学会使用PostMan工具发送请求和数据掌握SpringMVC如何接收请求、数据和响应结果掌握RESTfu......
  • String源码分析(四)
    ......