阅读须知
- Spring源码版本:4.3.8
- 文章中使用/* */注释的方法会做深入分析
正文
我们在使用SpringMVC时首先要配置web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-config.xml</param-value>
</context-param>
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
</welcome-file-list>
</web-app>
在web.xml中我们配置了 ContextLoaderListener,我们就以这个类作为入口分析 SpringMVC 的源码实现。ContextLoaderListener 实现了 ServletContextListener,我们知道在 servlet 容器启动之后会调用它的 contextInitialized 方法,我们来看ContextLoaderListener的 contextInitialized 方法的实现:
public void contextInitialized(ServletContextEvent event) {
/* 初始化 web 应用上下文 */
initWebApplicationContext(event.getServletContext());
}
ContextLoader:
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
// 在 web.xml 中配置了多个 ContextLoader 会抛异常
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);
servletContext.log("Initializing Spring root WebApplicationContext");
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
// 记录初始化开始时间
long startTime = System.currentTimeMillis();
try {
if (this.context == null) {
/* 创建 web 应用上下文 */
this.context = createWebApplicationContext(servletContext);
}
if (this.context instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
// 如果没有激活
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
// 如果配置了 parentContextKey,则设置父级上下文
ApplicationContext parent = loadParentContext(servletContext);
cwac.setParent(parent);
}
/* 配置并刷新上下文 */
configureAndRefreshWebApplicationContext(cwac, servletContext);
}
}
// 记录到 ServiceContext 中
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;
}
}
ContextLoader:
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
Class<?> contextClass = determineContextClass(sc); /* 寻找上下文类 */
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
}
// 反射初始化上下文对象
return (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
}
ContextLoader:
protected Class<?> determineContextClass(ServletContext servletContext) {
// 如果用户配置了 contextClass,则使用用户自定义的上下文类
String contextClassName = servletContext.getInitParameter(CONTEXT_CLASS_PARAM);
if (contextClassName != null) {
try {
return ClassUtils.forName(contextClassName, ClassUtils.getDefaultClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load custom context class [" + contextClassName + "]", ex);
}
}
else {
/* 没有自定义配置上下文类则使用默认的配置 */
contextClassName = defaultStrategies.getProperty(WebApplicationContext.class.getName());
try {
return ClassUtils.forName(contextClassName, ContextLoader.class.getClassLoader());
}
catch (ClassNotFoundException ex) {
throw new ApplicationContextException(
"Failed to load default context class [" + contextClassName + "]", ex);
}
}
}
ContextLoader:
private static final Properties defaultStrategies;
static {
try {
/* 在静态块中 defaultStrategies 加载了 ContextLoader.properties 配置文件 */
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, ContextLoader.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'ContextLoader.properties': " + ex.getMessage());
}
}
在ContextLoader.properties中的配置内容:
org.springframework.web.context.WebApplicationContext=org.springframework.web.context.support.XmlWebApplicationContext
也就是说默认的上下文类为 XmlWebApplicationContext,它实现了 ConfigurableWebApplicationContext,初始化对象之后并没有激活,所以下面会配置并刷新上下文:
ContextLoader:
protected void configureAndRefreshWebApplicationContext(ConfigurableWebApplicationContext wac, ServletContext sc) {
if (ObjectUtils.identityToString(wac).equals(wac.getId())) {
String idParam = sc.getInitParameter(CONTEXT_ID_PARAM);
// 如果用户自定义了 contextId 配置,则使用用户自定义的contextId
if (idParam != null) {
wac.setId(idParam);
}
else {
// 没有自定义则生成默认的 contextId
wac.setId(ConfigurableWebApplicationContext.APPLICATION_CONTEXT_ID_PREFIX +
ObjectUtils.getDisplayString(sc.getContextPath()));
}
}
wac.setServletContext(sc);
String configLocationParam = sc.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocationParam != null) {
// 将我们配置的 contextConfigLocation 设置到上下文对象中
wac.setConfigLocation(configLocationParam);
}
ConfigurableEnvironment env = wac.getEnvironment();
if (env instanceof ConfigurableWebEnvironment) {
// 为环境类初始化一些属性,主要为其设置 ServletContext 和ServletConfig
((ConfigurableWebEnvironment) env).initPropertySources(sc, null);
}
// 找到用户配置的 globalInitializerClasses 和 contextInitializerClasses
// 两个配置的类需要实现 ApplicationContextInitializer,并且按照 @Order 注解进行排序调用 initialize 方法
// 当我们需要对应用程序上下文进行一些编程初始化时可以使用它,例如根据上下文环境注册属性源或激活配置文件
customizeContext(sc, wac);
// 刷新,我们之前标签解析的文章都是在介绍这个刷新的过程,这里就不重复了
wac.refresh();
}
这里最后的刷新操作我们在之前的文章中用了大篇幅来介绍,其中有一步调用了postProcessBeanFactory方法,默认是空实现,而XmlWebApplicationContext的在初始化过程中覆盖了这个方法:
AbstractRefreshableWebApplicationContext:
protected void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// 添加 ServletContextAwareProcessor,用于为实现 ServletContextAware、ServletConfigAware 两个接口的 bean 设置相关资源
beanFactory.addBeanPostProcessor(new ServletContextAwareProcessor(this.servletContext, this.servletConfig));
// 添加两个忽略自动装配的接口
beanFactory.ignoreDependencyInterface(ServletContextAware.class);
beanFactory.ignoreDependencyInterface(ServletConfigAware.class);
/* 注册几个自定义的 scope,添加几个自动装配的接口 */
WebApplicationContextUtils.registerWebApplicationScopes(beanFactory, this.servletContext);
/* 注册几个环境 bean */
WebApplicationContextUtils.registerEnvironmentBeans(beanFactory, this.servletContext, this.servletConfig);
}
WebApplicationContextUtils:
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, ServletContext sc) {
// 注册几个自定义的 scope
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope(false));
beanFactory.registerScope(WebApplicationContext.SCOPE_GLOBAL_SESSION, new SessionScope(true));
if (sc != null) {
ServletContextScope appScope = new ServletContextScope(sc);
beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
sc.setAttribute(ServletContextScope.class.getName(), appScope);
}
// 添加几个自动装配的接口
beanFactory.registerResolvableDependency(ServletRequest.class, new RequestObjectFactory());
beanFactory.registerResolvableDependency(ServletResponse.class, new ResponseObjectFactory());
beanFactory.registerResolvableDependency(HttpSession.class, new SessionObjectFactory());
beanFactory.registerResolvableDependency(WebRequest.class, new WebRequestObjectFactory());
if (jsfPresent) {
FacesDependencyRegistrar.registerFacesDependencies(beanFactory);
}
}
WebApplicationContextUtils:
public static void registerEnvironmentBeans(
ConfigurableListableBeanFactory bf, ServletContext servletContext, ServletConfig servletConfig) {
if (servletContext != null && !bf.containsBean(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME)) {
// 注册 servletContext
bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext);
}
if (servletConfig != null && !bf.containsBean(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME)) {
// 注册 servletConfig
bf.registerSingleton(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME, servletConfig);
}
if (!bf.containsBean(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME)) {
Map<String, String> parameterMap = new HashMap<String, String>();
if (servletContext != null) {
Enumeration<?> paramNameEnum = servletContext.getInitParameterNames();
while (paramNameEnum.hasMoreElements()) {
String paramName = (String) paramNameEnum.nextElement();
parameterMap.put(paramName, servletContext.getInitParameter(paramName));
}
}
if (servletConfig != null) {
Enumeration<?> paramNameEnum = servletConfig.getInitParameterNames();
while (paramNameEnum.hasMoreElements()) {
String paramName = (String) paramNameEnum.nextElement();
parameterMap.put(paramName, servletConfig.getInitParameter(paramName));
}
}
// 注册 contextParameters
bf.registerSingleton(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME,
Collections.unmodifiableMap(parameterMap));
}
if (!bf.containsBean(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME)) {
Map<String, Object> attributeMap = new HashMap<String, Object>();
if (servletContext != null) {
Enumeration<?> attrNameEnum = servletContext.getAttributeNames();
while (attrNameEnum.hasMoreElements()) {
String attrName = (String) attrNameEnum.nextElement();
attributeMap.put(attrName, servletContext.getAttribute(attrName));
}
}
// 注册 contextAttributes
bf.registerSingleton(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME,
Collections.unmodifiableMap(attributeMap));
}
}
到这里上下文环境就初始化完了,我们在 web.xml 文件中还配置了 DispatcherServlet,它继承了 HttpServlet,我们知道,在 servlet 生命周期的初始化阶段,会调用它的 init 方法,我们在其父类HttpServletBean中找到了 init 方法的实现:
public final void init() throws ServletException {
if (logger.isDebugEnabled()) {
logger.debug("Initializing servlet '" + getServletName() + "'");
}
try {
// 解析 init-param 并封装到 PropertyValues 对象中,requiredProperties 用于配置一些必须的属性,如果检测到其中的属性没有设置值,就会抛出异常
PropertyValues pvs = new ServletConfigPropertyValues(getServletConfig(), this.requiredProperties);
// 创建 BeanWrapper
BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(this);
ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
// 注册自定义属性编辑器,遇到 Resource 类型的属性将使用 ResourceEditor 进行解析
bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
// 留给子类扩展对 BeanWrapper 的个性化初始化操作,默认空实现
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;
}
/* 子类实现初始化 */
initServletBean();
if (logger.isDebugEnabled()) {
logger.debug("Servlet '" + getServletName() + "' configured successfully");
}
}
FrameworkServlet:
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 {
/* 初始化web应用上下文 */
this.webApplicationContext = initWebApplicationContext();
// 默认空实现,留给子类扩展一些自定义的初始化需求
initFrameworkServlet();
}
catch (ServletException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
catch (RuntimeException ex) {
this.logger.error("Context initialization failed", ex);
throw ex;
}
if (this.logger.isInfoEnabled()) {
// 计算并打印初始化耗时
long elapsedTime = System.currentTimeMillis() - startTime;
this.logger.info("FrameworkServlet '" + getServletName() + "': initialization completed in " +
elapsedTime + " ms");
}
}
FrameworkServlet:
protected WebApplicationContext initWebApplicationContext() {
WebApplicationContext rootContext =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
WebApplicationContext wac = null;
// 这个 if 判断内的初始化逻辑,在上文已经介绍过
if (this.webApplicationContext != null) {
wac = this.webApplicationContext;
if (wac instanceof ConfigurableWebApplicationContext) {
ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) wac;
if (!cwac.isActive()) {
if (cwac.getParent() == null) {
cwac.setParent(rootContext);
}
configureAndRefreshWebApplicationContext(cwac);
}
}
}
if (wac == null) {
// 如果上下文为空则尝试从用户配置的 contextAttribute 属性加载 WebApplicationContext,这里要保证 WebApplicationContext 已经加载并存入 ServiceContext 中
wac = findWebApplicationContext();
}
if (wac == null) {
// 如果到这里上下文还是为空则创建本地默认的 XmlWebApplicationContext,创建和初始化过程与上文讲述的过程非常相似
wac = createWebApplicationContext(rootContext);
}
if (!this.refreshEventReceived) {
/* 默认子类实现初始化一些 servlet 需要的对象 */
onRefresh(wac);
}
if (this.publishContext) {
String attrName = getServletContextAttributeName();
// 将上下文对象设置到 ServletContext 的属性中
getServletContext().setAttribute(attrName, wac);
if (this.logger.isDebugEnabled()) {
this.logger.debug("Published WebApplicationContext of servlet '" + getServletName() +
"' as ServletContext attribute with name [" + attrName + "]");
}
}
return wac;
}
这里我们发现了另外一个创建应用上下文的分支,在文章开始的这种配置情况下,会进入这个判断,也就是说这里会调用createWebApplicationContext方法创建了另外一个上下文,而之前创建的上下文会作为它的父级上下文。
DispatcherServlet:
protected void onRefresh(ApplicationContext context) {
/* 初始化一些 servlet 需要的对象 */
initStrategies(context);
}
DispatcherServlet:
protected void initStrategies(ApplicationContext context) {
/* 初始化 MultipartResolver */
initMultipartResolver(context);
/* 初始化 LocaleResolver */
initLocaleResolver(context);
/* 初始化 ThemeResolver */
initThemeResolver(context);
/* 初始化 HandlerMapping */
initHandlerMappings(context);
/* 初始化 HandlerAdapter */
initHandlerAdapters(context);
/* 初始化 HandlerExceptionResolver */
initHandlerExceptionResolvers(context);
/* 初始化 RequestToViewNameTranslator */
initRequestToViewNameTranslator(context);
/* 初始化 ViewResolver */
initViewResolvers(context);
/* 初始化 FlashMapManager */
initFlashMapManager(context);
}
DispatcherServlet:
private void initMultipartResolver(ApplicationContext context) {
try {
// 获取到对应 bean 并赋值给对应的属性,MultipartResolver 主要用于解析文件上传的参数
this.multipartResolver = context.getBean(MULTIPART_RESOLVER_BEAN_NAME, MultipartResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Using MultipartResolver [" + this.multipartResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
this.multipartResolver = null;
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate MultipartResolver with name '" + MULTIPART_RESOLVER_BEAN_NAME +
"': no multipart request handling provided");
}
}
}
DispatcherServlet:
private void initLocaleResolver(ApplicationContext context) {
try {
// 获取到对应 bean 并赋值给对应的属性,LocaleResolver 主要用于支持国际化处理
this.localeResolver = context.getBean(LOCALE_RESOLVER_BEAN_NAME, LocaleResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Using LocaleResolver [" + this.localeResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// 没有则使用默认的策略
this.localeResolver = getDefaultStrategy(context, LocaleResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate LocaleResolver with name '" + LOCALE_RESOLVER_BEAN_NAME +
"': using default [" + this.localeResolver + "]");
}
}
}
DispatcherServlet:
private void initThemeResolver(ApplicationContext context) {
try {
// 获取到对应bean并赋值给对应的属性,ThemeResolver 主要用于控制网页风格的主题(比如静态资源,css 或图片等)
this.themeResolver = context.getBean(THEME_RESOLVER_BEAN_NAME, ThemeResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Using ThemeResolver [" + this.themeResolver + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// 没有则使用默认的策略
this.themeResolver = getDefaultStrategy(context, ThemeResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate ThemeResolver with name '" + THEME_RESOLVER_BEAN_NAME +
"': using default [" + this.themeResolver + "]");
}
}
}
DispatcherServlet:
private void initHandlerMappings(ApplicationContext context) {
this.handlerMappings = null;
// 默认为 true
if (this.detectAllHandlerMappings) {
// 加载所有 HandlerMapping 类型的bean,HandlerMapping 的作用在后文会详细说明
Map<String, HandlerMapping> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
if (!matchingBeans.isEmpty()) {
// 设置到 handlerMappings 属性中
this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values());
// 按照 @Order 注解排序
AnnotationAwareOrderComparator.sort(this.handlerMappings);
}
}
else {
// 如果不想加载所有的 HandlerMapping 类型 bean,只希望加载指定的,可以在 web.xml 的 init-param 配置中将 detectAllHandlerMappings 设置为 false
try {
// 获取到指定的 bean 并赋值给对应的属性
HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
this.handlerMappings = Collections.singletonList(hm);
}
catch (NoSuchBeanDefinitionException ex) {
}
}
if (this.handlerMappings == null) {
// 没有则使用默认的策略
this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
}
}
}
DispatcherServlet:
private void initHandlerAdapters(ApplicationContext context) {
this.handlerAdapters = null;
// 默认为 true
if (this.detectAllHandlerAdapters) {
// 加载所有 HandlerAdapter 类型的 bean,HandlerAdapter 的作用在后文会详细说明
Map<String, HandlerAdapter> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
if (!matchingBeans.isEmpty()) {
// 设置到 handlerAdapters 属性中
this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values());
// 按照 @Order 注解排序
AnnotationAwareOrderComparator.sort(this.handlerAdapters);
}
}
else {
// 如果不想加载所有的 HandlerAdapter 类型 bean,只希望加载指定的,可以在 web.xml 的 init-param 配置中将 detectAllHandlerAdapters 设置为 false
try {
// 获取到指定的 bean 并赋值给对应的属性
HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
this.handlerAdapters = Collections.singletonList(ha);
}
catch (NoSuchBeanDefinitionException ex) {
}
}
if (this.handlerAdapters == null) {
// 没有则使用默认的策略
this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
}
}
}
DispatcherServlet:
private void initHandlerExceptionResolvers(ApplicationContext context) {
this.handlerExceptionResolvers = null;
// 默认为 true
if (this.detectAllHandlerExceptionResolvers) {
// 加载所有 HandlerExceptionResolver 类型的 bean,HandlerExceptionResolver 的作用在后文会详细说明
Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
.beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
// 设置到 handlerExceptionResolvers 属性中
this.handlerExceptionResolvers = new ArrayList<HandlerExceptionResolver>(matchingBeans.values());
// 按照 @Order 注解排序
AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers);
}
}
else {
// 如果不想加载所有的 HandlerExceptionResolver 类型 bean,只希望加载指定的,可以在 web.xml 的 init-param 配置中将 detectAllHandlerExceptionResolvers 设置为 false
try {
// 获取到指定的 bean 并赋值给对应的属性
HandlerExceptionResolver her =
context.getBean(HANDLER_EXCEPTION_RESOLVER_BEAN_NAME, HandlerExceptionResolver.class);
this.handlerExceptionResolvers = Collections.singletonList(her);
}
catch (NoSuchBeanDefinitionException ex) {
}
}
if (this.handlerExceptionResolvers == null) {
// 没有则使用默认的策略
this.handlerExceptionResolvers = getDefaultStrategies(context, HandlerExceptionResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("No HandlerExceptionResolvers found in servlet '" + getServletName() + "': using default");
}
}
}
DispatcherServlet:
private void initRequestToViewNameTranslator(ApplicationContext context) {
try {
// 获取到对应bean并赋值给对应的属性,默认情况下会翻译路径返回一个视图
this.viewNameTranslator =
context.getBean(REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME, RequestToViewNameTranslator.class);
if (logger.isDebugEnabled()) {
logger.debug("Using RequestToViewNameTranslator [" + this.viewNameTranslator + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// 没有则使用默认的策略
this.viewNameTranslator = getDefaultStrategy(context, RequestToViewNameTranslator.class);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate RequestToViewNameTranslator with name '" +
REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME + "': using default [" + this.viewNameTranslator +
"]");
}
}
}
DispatcherServlet:
private void initViewResolvers(ApplicationContext context) {
this.viewResolvers = null;
// 默认为 true
if (this.detectAllViewResolvers) {
// 加载所有 ViewResolver 类型的 bean,ViewResolver 的作用在后文会详细说明
Map<String, ViewResolver> matchingBeans =
BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false);
if (!matchingBeans.isEmpty()) {
// 设置到 viewResolvers 属性中
this.viewResolvers = new ArrayList<ViewResolver>(matchingBeans.values());
// 按照 @Order 注解排序
AnnotationAwareOrderComparator.sort(this.viewResolvers);
}
}
else {
// 如果不想加载所有的 ViewResolver 类型 bean,只希望加载指定的,可以在 web.xml 的 init-param 配置中将 detectAllViewResolvers 设置为 false
try {
// 获取到指定的 bean 并赋值给对应的属性
ViewResolver vr = context.getBean(VIEW_RESOLVER_BEAN_NAME, ViewResolver.class);
this.viewResolvers = Collections.singletonList(vr);
}
catch (NoSuchBeanDefinitionException ex) {
}
}
if (this.viewResolvers == null) {
// 没有则使用默认的策略
this.viewResolvers = getDefaultStrategies(context, ViewResolver.class);
if (logger.isDebugEnabled()) {
logger.debug("No ViewResolvers found in servlet '" + getServletName() + "': using default");
}
}
}
DispatcherServlet:
private void initFlashMapManager(ApplicationContext context) {
try {
// 获取到对应的 bean 并赋值给对应的属性,FlashMapManager 的作用主要是提供了一个请求存储属性,可供其他请求使用,例如重定向之后还能使用重定向之前暂存的属性
this.flashMapManager = context.getBean(FLASH_MAP_MANAGER_BEAN_NAME, FlashMapManager.class);
if (logger.isDebugEnabled()) {
logger.debug("Using FlashMapManager [" + this.flashMapManager + "]");
}
}
catch (NoSuchBeanDefinitionException ex) {
// 没有则使用默认的策略
this.flashMapManager = getDefaultStrategy(context, FlashMapManager.class);
if (logger.isDebugEnabled()) {
logger.debug("Unable to locate FlashMapManager with name '" +
FLASH_MAP_MANAGER_BEAN_NAME + "': using default [" + this.flashMapManager + "]");
}
}
}
在上面的初始化过程中几乎都有一个默认的初始化策略,默认的初始化策略会加载 DispatcherServlet.properties 配置文件,并创建对应的 bean 返回,我们来看一下其中的配置:
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.annotation.DefaultAnnotationHandlerMapping
org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\
org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\
org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver,\
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
下篇文章我们会介绍 Spring MVC 的执行过程和这些默认配置在其中的应用。