首页 » Java » Spring源码解析之Spring MVC(一)

Spring源码解析之Spring MVC(一)

原文 http://blog.csdn.net/heroqiang/article/details/79037456

2018-01-12 02:00:37阅读(373)

阅读须知

文章中使用//单行注释做代码的简单注释,而/**/多行注释的代码会做深入分析,为了避免篇幅过长,删掉了Spring原来的注释和空行,建议配合Spring源代码进行阅读,本文对应的Spring源码的版本为4.3.8。

本文的主要内容是分析Spring MVC配置解析和执行前的准备工作源码。

正文

我们在使用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) {
    initWebApplicationContext(event.getServletContext()); /*初始化web应用上下文*/
}
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);
            }
        }
        servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context); //记录到ServiceContext中
        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) {
        wac.setConfigLocation(configLocationParam); //将我们配置的contextConfigLocation设置到上下文对象中
    }
    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)) {
        bf.registerSingleton(WebApplicationContext.SERVLET_CONTEXT_BEAN_NAME, servletContext); //注册servletContext
    }
    if (servletConfig != null && !bf.containsBean(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME)) {
        bf.registerSingleton(ConfigurableWebApplicationContext.SERVLET_CONFIG_BEAN_NAME, servletConfig); //注册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));
            }
        }
        bf.registerSingleton(WebApplicationContext.CONTEXT_PARAMETERS_BEAN_NAME,
                Collections.unmodifiableMap(parameterMap)); //注册contextParameters
    }
    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));
            }
        }
        bf.registerSingleton(WebApplicationContext.CONTEXT_ATTRIBUTES_BEAN_NAME,
                Collections.unmodifiableMap(attributeMap)); //注册contextAttributes
    }
}

到这里上下文环境就初始化完了,我们在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 bw = PropertyAccessorFactory.forBeanPropertyAccess(this); //创建BeanWrapper
        ResourceLoader resourceLoader = new ServletContextResourceLoader(getServletContext());
        //注册自定义属性编辑器,遇到Resource类型的属性将使用ResourceEditor进行解析
        bw.registerCustomEditor(Resource.class, new ResourceEditor(resourceLoader, getEnvironment()));
        initBeanWrapper(bw); //留给子类扩展对BeanWrapper的个性化初始化操作,默认空实现
        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 {
        this.webApplicationContext = initWebApplicationContext(); /*初始化web应用上下文*/
        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判断,初始化流程几乎是完全一样的
            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) {
        onRefresh(wac); /*默认子类实现初始化一些servlet需要的对象*/
    }
    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;
}

DispatcherServlet:

protected void onRefresh(ApplicationContext context) {
    initStrategies(context); /*初始化一些servlet需要的对象*/
}

DispatcherServlet:

protected void initStrategies(ApplicationContext context) {
    initMultipartResolver(context); /*初始化MultipartResolver*/
    initLocaleResolver(context); /*初始化LocaleResolver*/
    initThemeResolver(context); /*初始化ThemeResolver*/
    initHandlerMappings(context); /*初始化HandlerMapping*/
    initHandlerAdapters(context); /*初始化HandlerAdapter*/
    initHandlerExceptionResolvers(context); /*初始化HandlerExceptionResolver*/
    initRequestToViewNameTranslator(context); /*初始化RequestToViewNameTranslator*/
    initViewResolvers(context); /*初始化ViewResolver*/
    initFlashMapManager(context); /*初始化FlashMapManager*/
}

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;
    if (this.detectAllHandlerMappings) { //默认为true
        Map<String, HandlerMapping> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); //加载所有HandlerMapping类型的bean,HandlerMapping的作用在后文会详细说明
        if (!matchingBeans.isEmpty()) {
            this.handlerMappings = new ArrayList<HandlerMapping>(matchingBeans.values()); //设置到handlerMappings属性中
            AnnotationAwareOrderComparator.sort(this.handlerMappings); //按照@Order注解排序
        }
    }
    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;
    if (this.detectAllHandlerAdapters) { //默认为true
        Map<String, HandlerAdapter> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false); //加载所有HandlerAdapter类型的bean,HandlerAdapter的作用在后文会详细说明
        if (!matchingBeans.isEmpty()) {
            this.handlerAdapters = new ArrayList<HandlerAdapter>(matchingBeans.values()); //设置到handlerAdapters属性中
            AnnotationAwareOrderComparator.sort(this.handlerAdapters); //按照@Order注解排序
        }
    }
    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;
    if (this.detectAllHandlerExceptionResolvers) { //默认为true
        Map<String, HandlerExceptionResolver> matchingBeans = BeanFactoryUtils
                .beansOfTypeIncludingAncestors(context, HandlerExceptionResolver.class, true, false); //加载所有HandlerExceptionResolver类型的bean,HandlerExceptionResolver的作用在后文会详细说明
        if (!matchingBeans.isEmpty()) {
            this.handlerExceptionResolvers = new ArrayList<HandlerExceptionResolver>(matchingBeans.values()); //设置到handlerExceptionResolvers 属性中
            AnnotationAwareOrderComparator.sort(this.handlerExceptionResolvers); //按照@Order注解排序
        }
    }
    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;
    if (this.detectAllViewResolvers) { //默认为true
        Map<String, ViewResolver> matchingBeans =
                BeanFactoryUtils.beansOfTypeIncludingAncestors(context, ViewResolver.class, true, false); //加载所有ViewResolver类型的bean,ViewResolver的作用在后文会详细说明
        if (!matchingBeans.isEmpty()) {
            this.viewResolvers = new ArrayList<ViewResolver>(matchingBeans.values()); //设置到viewResolvers 属性中
            AnnotationAwareOrderComparator.sort(this.viewResolvers); //按照@Order注解排序
        }
    }
    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的执行过程和这些默认配置在其中的应用。

最新发布

CentOS专题

关于本站

5ibc.net旗下博客站精品博文小部分原创、大部分从互联网收集整理。尊重作者版权、传播精品博文,让更多编程爱好者知晓!

小提示

按 Ctrl+D 键,
把本文加入收藏夹