Spring MVC <mvc:view-resolvers> 标签解析

Spring MVC <mvc:view-resolvers> 标签解析

<mvc:view-resolvers>的解析类是 ViewResolversBeanDefinitionParser。关键部分的代码:

public BeanDefinition parse(Element element, ParserContext context) {
    Object source = context.extractSource(element);
    context.pushContainingComponent(new CompositeComponentDefinition(element.getTagName(), source));

    ManagedList<Object> resolvers = new ManagedList<Object>(4);
    resolvers.setSource(context.extractSource(element));
    String[] names = new String[] {"jsp", "tiles", "bean-name", "freemarker", "velocity", "groovy", "bean", "ref"};

    for (Element resolverElement : DomUtils.getChildElementsByTagName(element, names)) {
        String name = resolverElement.getLocalName();
        if ("bean".equals(name) || "ref".equals(name)) {
            resolvers.add(context.getDelegate().parsePropertySubElement(resolverElement, null));
            continue;
        }
        RootBeanDefinition resolverBeanDef = null;
        if ("jsp".equals(name)) {
            resolverBeanDef = new RootBeanDefinition(InternalResourceViewResolver.class);
            resolverBeanDef.getPropertyValues().add("prefix", "/WEB-INF/");
            resolverBeanDef.getPropertyValues().add("suffix", ".jsp");
            addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
        }
        else if ("tiles".equals(name)) {
            resolverBeanDef = new RootBeanDefinition(TilesViewResolver.class);
            addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
        }
        else if ("freemarker".equals(name)) {
            resolverBeanDef = new RootBeanDefinition(FreeMarkerViewResolver.class);
            resolverBeanDef.getPropertyValues().add("suffix", ".ftl");
            addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
        }
        else if ("velocity".equals(name)) {
            resolverBeanDef = new RootBeanDefinition(VelocityViewResolver.class);
            resolverBeanDef.getPropertyValues().add("suffix", ".vm");
            addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
        }
        else if ("groovy".equals(name)) {
            resolverBeanDef = new RootBeanDefinition(GroovyMarkupViewResolver.class);
            resolverBeanDef.getPropertyValues().add("suffix", ".tpl");
            addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
        }
        else if ("bean-name".equals(name)) {
            resolverBeanDef = new RootBeanDefinition(BeanNameViewResolver.class);
        }
        else {
            // Should never happen
            throw new IllegalStateException("Unexpected element name: " + name);
        }
        resolverBeanDef.setSource(source);
        resolverBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
        resolvers.add(resolverBeanDef);
    }

    String beanName = VIEW_RESOLVER_BEAN_NAME;
    RootBeanDefinition compositeResolverBeanDef = new RootBeanDefinition(ViewResolverComposite.class);
    compositeResolverBeanDef.setSource(source);
    compositeResolverBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

    names = new String[] {"content-negotiation"};
    List<Element> contentnNegotiationElements = DomUtils.getChildElementsByTagName(element, names);
    if (contentnNegotiationElements.isEmpty()) {
        compositeResolverBeanDef.getPropertyValues().add("viewResolvers", resolvers);
    }
    else if (contentnNegotiationElements.size() == 1) {
        BeanDefinition beanDef = createContentNegotiatingViewResolver(contentnNegotiationElements.get(0), context);
        beanDef.getPropertyValues().add("viewResolvers", resolvers);
        ManagedList<Object> list = new ManagedList<Object>(1);
        list.add(beanDef);
        compositeResolverBeanDef.getPropertyValues().add("order", Ordered.HIGHEST_PRECEDENCE);
        compositeResolverBeanDef.getPropertyValues().add("viewResolvers", list);
    }
    else if (contentnNegotiationElements.size() > 1) {
        throw new IllegalArgumentException("Only one <content-negotiation> element is allowed.");
    }

    if (element.hasAttribute("order")) {
        compositeResolverBeanDef.getPropertyValues().add("order", element.getAttribute("order"));
    }

    context.getReaderContext().getRegistry().registerBeanDefinition(beanName, compositeResolverBeanDef);
    context.registerComponent(new BeanComponentDefinition(compositeResolverBeanDef, beanName));
    context.popAndRegisterContainingComponent();
    return null;
}

如下的<mvc:view-resolvers>标签的配置:

<!-- 配置视图解析器-->
<mvc:view-resolvers>
    <mvc:content-negotiation>
        <mvc:default-views>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView">
                <property name="jsonpParameterNames">
                    <set>
                        <value>jsonp</value>
                        <value>callback</value>
                    </set>
                </property>
            </bean>
        </mvc:default-views>
    </mvc:content-negotiation>
    <!-- JSP的视图解析器-->
    <mvc:jsp prefix="/WEB-INF/views/"/>
</mvc:view-resolvers>

那么他是如何解析的呢?通过debug代码可以很清晰的了解到。

关键的流程如下,首先解析<mvc:view-resolvers>标签下的子标签,包括以下子标签:

 String[] names = new String[] {"jsp", "tiles", "bean-name", "freemarker", "velocity", "groovy", "bean", "ref"};

对于这些子标签的处理,如下

if ("jsp".equals(name)) {
    resolverBeanDef = new RootBeanDefinition(
        InternalResourceViewResolver.class);
    resolverBeanDef.getPropertyValues().add("prefix", "/WEB-INF/");
    resolverBeanDef.getPropertyValues().add("suffix", ".jsp");
    addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
} else if ("tiles".equals(name)) {
    resolverBeanDef = new RootBeanDefinition(TilesViewResolver.class);
    addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
} else if ("freemarker".equals(name)) {
    resolverBeanDef = new RootBeanDefinition(
        FreeMarkerViewResolver.class);
    resolverBeanDef.getPropertyValues().add("suffix", ".ftl");
    addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
} else if ("velocity".equals(name)) {
    resolverBeanDef = new RootBeanDefinition(VelocityViewResolver.class);
    resolverBeanDef.getPropertyValues().add("suffix", ".vm");
    addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
} else if ("groovy".equals(name)) {
    resolverBeanDef = new RootBeanDefinition(
        GroovyMarkupViewResolver.class);
    resolverBeanDef.getPropertyValues().add("suffix", ".tpl");
    addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
} else if ("bean-name".equals(name)) {
    resolverBeanDef = new RootBeanDefinition(BeanNameViewResolver.class);
} else {
    // Should never happen
    throw new IllegalStateException("Unexpected element name: " + name);
}

如何配置了这几种常见的视图解析器, 那么在这里就会实例化(注入)相应的视图解析器。

比较常见的视图解析器有:

  1. InternalResourceViewResolver:UrlBasedViewResolver 的子类,通常用于查找 JSP(类 InternalResourceView)和 JSTL(类 JstlView,InternalResourceView 的子类)等视图。

  2. TilesViewResolver:(一种动态模板视图解析器)

  3. FreeMarkerViewResolver:(FreeMarker的视图解析器)

  4. VelocityViewResolver:(Velocity的视图解析器)

  5. GroovyMarkupViewResolver:(基于Groovy 的一种DSL风格的模板视图解析器)

  6. BeanNameViewResolver:

 

然后是处理其他的子标签,只有content-negotiation子标签:

names = new String[] {"content-negotiation"};

处理content-negotiation子标签的代码如下,

String beanName = VIEW_RESOLVER_BEAN_NAME;
RootBeanDefinition compositeResolverBeanDef = new RootBeanDefinition(
    ViewResolverComposite.class);
compositeResolverBeanDef.setSource(source);
compositeResolverBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);

names = new String[] { "content-negotiation" };
List<Element> contentnNegotiationElements = DomUtils
    .getChildElementsByTagName(element, names);
if (contentnNegotiationElements.isEmpty()) {
    compositeResolverBeanDef.getPropertyValues().add("viewResolvers",
        resolvers);
} else if (contentnNegotiationElements.size() == 1) {
    BeanDefinition beanDef = createContentNegotiatingViewResolver(
        contentnNegotiationElements.get(0), context);
    beanDef.getPropertyValues().add("viewResolvers", resolvers);
    ManagedList<Object> list = new ManagedList<Object>(1);
    list.add(beanDef);
    compositeResolverBeanDef.getPropertyValues().add("order",
        Ordered.HIGHEST_PRECEDENCE);
    compositeResolverBeanDef.getPropertyValues().add("viewResolvers",
        list);
} else if (contentnNegotiationElements.size() > 1) {
    throw new IllegalArgumentException(
        "Only one <content-negotiation> element is allowed.");
}

再来看他是怎么创建 ContentNegotiatingViewResolver 的 。

BeanDefinition beanDef = createContentNegotiatingViewResolver(contentnNegotiationElements.get(0), context);

方法createContentNegotiatingViewResolver

private BeanDefinition createContentNegotiatingViewResolver(Element resolverElement, ParserContext context) {
    RootBeanDefinition beanDef = new RootBeanDefinition(ContentNegotiatingViewResolver.class);
    beanDef.setSource(context.extractSource(resolverElement));
    beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
    MutablePropertyValues values = beanDef.getPropertyValues();
    //<content-negotiation>标签下的子标签 default-views
    List<Element> elements = DomUtils.getChildElementsByTagName(resolverElement, new String[] {"default-views"});
    if (!elements.isEmpty()) {
        ManagedList<Object> list = new ManagedList<Object>();
        for (Element element : DomUtils.getChildElementsByTagName(elements.get(0), "bean", "ref")) {
            list.add(context.getDelegate().parsePropertySubElement(element, null));
        }
        values.add("defaultViews", list);
    }
    if (resolverElement.hasAttribute("use-not-acceptable")) {
        values.add("useNotAcceptableStatusCode", resolverElement.getAttribute("use-not-acceptable"));
    }
    String beanName = AnnotationDrivenBeanDefinitionParser.CONTENT_NEGOTIATION_MANAGER_BEAN_NAME;
    if (context.getRegistry().containsBeanDefinition(beanName)) {
        values.add("contentNegotiationManager", new RuntimeBeanReference(beanName));
    }
    return beanDef;
}

至此 ,<mvc:view-resolvers>标签就处理完了。

要注意到,如果没有配置content-negotiation子标签,那么只有ViewResolverComposite的实例对象包含了所有配置的视图解析器。

compositeResolverBeanDef.getPropertyValues().add("viewResolvers",resolvers);

否则,那么创建ContentNegotiatingViewResolver,并设置ContentNegotiatingViewResolver的viewResolvers的集合,同时设置 ViewResolverComposite 的viewResolvers集合,

但只包含一个ContentNegotiatingViewResolver的实例。

 BeanDefinition beanDef = createContentNegotiatingViewResolver(
        contentnNegotiationElements.get(0), context);
    beanDef.getPropertyValues().add("viewResolvers", resolvers);
    ManagedList<Object> list = new ManagedList<Object>(1);
    list.add(beanDef);
    compositeResolverBeanDef.getPropertyValues().add("order",
        Ordered.HIGHEST_PRECEDENCE);
    compositeResolverBeanDef.getPropertyValues().add("viewResolvers",
        list);

=================END=================

转载于:https://my.oschina.net/xinxingegeya/blog/480338

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值