Spring MVC <mvc:view-resolvers> 標籤解析web
<mvc:view-resolvers>的解析類是 ViewResolversBeanDefinitionParser。關鍵部分的代碼:spring
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>標籤的配置:json
<!-- 配置視圖解析器--> <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
關鍵的流程以下,首先解析<mvc:view-resolvers>標籤下的子標籤,包括如下子標籤:app
String[] names = new String[] {"jsp", "tiles", "bean-name", "freemarker", "velocity", "groovy", "bean", "ref"};
對於這些子標籤的處理,以下jsp
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); }
如何配置了這幾種常見的視圖解析器, 那麼在這裏就會實例化(注入)相應的視圖解析器。jsonp
比較常見的視圖解析器有:spa
InternalResourceViewResolver:UrlBasedViewResolver 的子類,一般用於查找 JSP(類 InternalResourceView)和 JSTL(類 JstlView,InternalResourceView 的子類)等視圖。debug
TilesViewResolver:(一種動態模板視圖解析器)code
FreeMarkerViewResolver:(FreeMarker的視圖解析器)
VelocityViewResolver:(Velocity的視圖解析器)
GroovyMarkupViewResolver:(基於Groovy 的一種DSL風格的模板視圖解析器)
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=================