1. 程式人生 > >springmvc原始碼解析MvcNamespaceHandler之<mvc:view-resolvers>

springmvc原始碼解析MvcNamespaceHandler之<mvc:view-resolvers>

開發十年,就只剩下這套架構體系了! >>>   

說在前面

本次主要介紹springmvc配置解析。

 

springmvc配置解析

本次介紹MvcNamespaceHandler。

進入到這個方法org.springframework.web.servlet.config.ViewResolversBeanDefinitionParser#parse

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", "script-template", "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;
         if ("jsp".equals(name)) {
//          註冊InternalResourceViewResolver檢視解析器bean定義
            resolverBeanDef = new RootBeanDefinition(InternalResourceViewResolver.class);
//          檢視檔案字首
            resolverBeanDef.getPropertyValues().add("prefix", "/WEB-INF/");
//          檢視檔案字尾
            resolverBeanDef.getPropertyValues().add("suffix", ".jsp");
//          新增基於url的檢視屬性 ->
            addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
         }
         else if ("tiles".equals(name)) {
            resolverBeanDef = new RootBeanDefinition(TilesViewResolver.class);
            addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
         }
         else if ("freemarker".equals(name)) {
//          解析FreeMarkerViewResolver bean定義
            resolverBeanDef = new RootBeanDefinition(FreeMarkerViewResolver.class);
            resolverBeanDef.getPropertyValues().add("suffix", ".ftl");
            addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
         }
         else if ("velocity".equals(name)) {
//          解析VelocityViewResolver bean定義
            resolverBeanDef = new RootBeanDefinition(org.springframework.web.servlet.view.velocity.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 ("script-template".equals(name)) {
            resolverBeanDef = new RootBeanDefinition(ScriptTemplateViewResolver.class);
            addUrlBasedViewResolverProperties(resolverElement, resolverBeanDef);
         }
         else if ("bean-name".equals(name)) {
//          解析BeanNameViewResolver bean定義
            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;
//    解析ViewResolverComposite bean定義
      RootBeanDefinition compositeResolverBeanDef = new RootBeanDefinition(ViewResolverComposite.class);
      compositeResolverBeanDef.setSource(source);
      compositeResolverBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
      names = new String[] {"content-negotiation"};
      List<Element> contentNegotiationElements = DomUtils.getChildElementsByTagName(element, names);
      if (contentNegotiationElements.isEmpty()) {
         compositeResolverBeanDef.getPropertyValues().add("viewResolvers", resolvers);
      }
      else if (contentNegotiationElements.size() == 1) {
//       建立媒體型別檢視解析器 ->
         BeanDefinition beanDef = createContentNegotiatingViewResolver(contentNegotiationElements.get(0), context);
//       組合檢視解析器,解析viewResolvers屬性值
         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 {
         throw new IllegalArgumentException("Only one <content-negotiation> element is allowed.");
      }

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

//    註冊mvcViewResolver bean定義
      context.getReaderContext().getRegistry().registerBeanDefinition(beanName, compositeResolverBeanDef);
      context.registerComponent(new BeanComponentDefinition(compositeResolverBeanDef, beanName));
      context.popAndRegisterContainingComponent();
      return null;
   }

進入到這個方法org.springframework.web.servlet.config.ViewResolversBeanDefinitionParser#addUrlBasedViewResolverProperties

private void addUrlBasedViewResolverProperties(Element element, RootBeanDefinition beanDefinition) {
   if (element.hasAttribute("prefix")) {
      beanDefinition.getPropertyValues().add("prefix", element.getAttribute("prefix"));
   }
   if (element.hasAttribute("suffix")) {
      beanDefinition.getPropertyValues().add("suffix", element.getAttribute("suffix"));
   }
   if (element.hasAttribute("cache-views")) {
      beanDefinition.getPropertyValues().add("cache", element.getAttribute("cache-views"));
   }
   if (element.hasAttribute("view-class")) {
      beanDefinition.getPropertyValues().add("viewClass", element.getAttribute("view-class"));
   }
   if (element.hasAttribute("view-names")) {
      beanDefinition.getPropertyValues().add("viewNames", element.getAttribute("view-names"));
   }
}

往上返回到這個方法org.springframework.web.servlet.config.ViewResolversBeanDefinitionParser#createContentNegotiatingViewResolver

private BeanDefinition createContentNegotiatingViewResolver(Element resolverElement, ParserContext context) {
//    註冊ContentNegotiatingViewResolver bean定義
      RootBeanDefinition beanDef = new RootBeanDefinition(ContentNegotiatingViewResolver.class);
      beanDef.setSource(context.extractSource(resolverElement));
      beanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
      MutablePropertyValues values = beanDef.getPropertyValues();
//    預設檢視
      List<Element> elements = DomUtils.getChildElementsByTagName(resolverElement, "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"));
      }
//    獲取媒體型別管理器bean定義 ->
      Object manager = MvcNamespaceUtils.getContentNegotiationManager(context);
      if (manager != null) {
         values.add("contentNegotiationManager", manager);
      }
      return beanDef;
   }

進入到這個方法org.springframework.web.servlet.config.MvcNamespaceUtils#getContentNegotiationManager

public static Object getContentNegotiationManager(ParserContext context) {
      String name = AnnotationDrivenBeanDefinitionParser.HANDLER_MAPPING_BEAN_NAME;
      if (context.getRegistry().containsBeanDefinition(name)) {
         BeanDefinition handlerMappingBeanDef = context.getRegistry().getBeanDefinition(name);
//       從RequestMappingHandlerMapping bean定義中獲取
         return handlerMappingBeanDef.getPropertyValues().get("contentNegotiationManager");
      }
      name = AnnotationDrivenBeanDefinitionParser.CONTENT_NEGOTIATION_MANAGER_BEAN_NAME;
      if (context.getRegistry().containsBeanDefinition(name)) {
         return new RuntimeBeanReference(name);
      }
      return null;
   }

往上返回到這個方法org.springframework.web.servlet.config.ViewResolversBeanDefinitionParser#parse

 

說到最後

本次原始碼解析僅代表個人觀點,僅供參