spring是如何加载可用的ViewResolver的?

Spring Web MVC 视图解析

Spring web MVC 框架同其它web MVC 框架一样,是请求驱动的(request driven),围绕中心Servlet设计的。中心Servlet会分配请求到各个Controllers,以及提供其它功能。Spring的DispatcherServlet就是这种中心Servlet,但做的更多。所有MVC框架都提供定位视图(address views)的机制,Spring提供view resolvers,让你能够在浏览器上渲染models,而不会把你束缚在某一特定的视图技术上。有2个接口(Interface)对于Spring处理视图来说是很重要的,一个是ViewResolver,另一个是View。 ViewResolver提供视图名称与实际视图的映射关系,View接口定位请求准备和请求处理到视图技术上。Spring规定,Controller中的所有handler方法,必须解析到一个逻辑视图,可以是显式的(通过返回String、View或ModelView)或者是隐式的(基于协商 based on conventions)。在Spring中,视图由逻辑视图名称定位,然后由一个view resolver解析。

Spring自带的视图解析器

Spring自身带有若干种view resolver,比如:AbstractCachingViewResolver、XmlViewResolver、ResourceBundleViewResolver、UrlBasedViewResolver、InternalResourceViewResolver、VelocityViewResolver、FreeMarkerViewResolver
、ContentNegotiatingViewResolver,你可以使用1种,或链式使用多种。使用方法就是在你的*-Servlet.xml配置文件种加入相关的bean。举例如下:

<bean id="jspViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
    <property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
    <property name="prefix" value="/WEB-INF/jsp/"/>
    <property name="suffix" value=".jsp"/>
</bean>
<bean id="excelViewResolver" class="org.springframework.web.servlet.view.XmlViewResolver">
    <property name="order" value="1"/>
    <property name="location" value="/WEB-INF/views.xml"/>
</bean>

J2EE环境下视图解析器的加载

那么,问题是,Spring是如何从容器中感知到我们想要使用哪些ViewResoler的呢? 答案就在于DispatcherServlet类中的initViewResolvers方法。

DispatcherServlet.java中有一个私有方法,名为initViewResolvers,代码片段如下,就是用来初始化所有ViewResolvers的。

    /**
     * Initialize the ViewResolvers used by this class.
     * <p>If no ViewResolver beans are defined in the BeanFactory for this
     * namespace, we default to InternalResourceViewResolver.
     */
    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<ViewResolver>(matchingBeans.values());
                // We keep ViewResolvers in sorted order.
                OrderComparator.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.isDebugEnabled()) {
                logger.debug("No ViewResolvers found in servlet '" + getServletName() + "': using default");
            }
        }
    }

如果detectAllViewResolvers属性被设置为true的话,就会触发DispatcherServlet从ApplicationContext中加载所有基类为ViewResolver的Beans,然后存入viewResolvers列表。
(initViewResolvers会被确保在WebApplicationContext被初始化好了以后才会被调用的)

    原文作者:执着的慢行者
    原文地址: https://segmentfault.com/a/1190000011760118
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞