说在前面

本次主要介绍springmvc配置解析<mvc:freemarker-configurer/>、<mvc:velocity-configurer/>、 <mvc:cors>。关注“天河聊技术”更多中间件源码解析。

springmvc配置解析

本次介绍MvcNamespaceHandler。

进入到这个方法org.springframework.web.servlet.config.FreeMarkerConfigurerBeanDefinitionParser#doParse

@Override
   protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
//    解析template-loader-path属性值
      List<Element> childElements = DomUtils.getChildElementsByTagName(element, "template-loader-path");
      if (!childElements.isEmpty()) {
         List<String> locations = new ArrayList<String>(childElements.size());
         for (Element childElement : childElements) {
//          解析location属性值
            locations.add(childElement.getAttribute("location"));
         }
         if (locations.isEmpty()) {
//          视图文件前缀
            locations.add("/WEB-INF/");
         }
         builder.addPropertyValue("templateLoaderPaths", StringUtils.toStringArray(locations));
      }
   }

进入到这个方法org.springframework.web.servlet.config.VelocityConfigurerBeanDefinitionParser#postProcess

@Override
   protected void postProcess(BeanDefinitionBuilder builder, Element element) {
      if (!builder.getBeanDefinition().hasAttribute("resourceLoaderPath")) {
//       默认视图路径
         builder.getBeanDefinition().setAttribute("resourceLoaderPath", "/WEB-INF/");
      }
   }

进入到这个方法org.springframework.web.servlet.config.CorsBeanDefinitionParser#parse

@Override
   public BeanDefinition parse(Element element, ParserContext parserContext) {

      Map<String, CorsConfiguration> corsConfigurations = new LinkedHashMap<String, CorsConfiguration>();
//    解析映射
      List<Element> mappings = DomUtils.getChildElementsByTagName(element, "mapping");
      if (mappings.isEmpty()) {
//       添加允许的默认值 ->
         CorsConfiguration config = new CorsConfiguration().applyPermitDefaultValues();
//       如果是空,所有路径都支持跨域
         corsConfigurations.put("/**", config);
      }
      else {
         for (Element mapping : mappings) {
            CorsConfiguration config = new CorsConfiguration();
//          允许跨的域
            if (mapping.hasAttribute("allowed-origins")) {
               String[] allowedOrigins = StringUtils.tokenizeToStringArray(mapping.getAttribute("allowed-origins"), ",");
               config.setAllowedOrigins(Arrays.asList(allowedOrigins));
            }
//          允许跨域的方法
            if (mapping.hasAttribute("allowed-methods")) {
               String[] allowedMethods = StringUtils.tokenizeToStringArray(mapping.getAttribute("allowed-methods"), ",");
               config.setAllowedMethods(Arrays.asList(allowedMethods));
            }
//          允许跨域的headers
            if (mapping.hasAttribute("allowed-headers")) {
               String[] allowedHeaders = StringUtils.tokenizeToStringArray(mapping.getAttribute("allowed-headers"), ",");
               config.setAllowedHeaders(Arrays.asList(allowedHeaders));
            }
//          暴露的headers
            if (mapping.hasAttribute("exposed-headers")) {
               String[] exposedHeaders = StringUtils.tokenizeToStringArray(mapping.getAttribute("exposed-headers"), ",");
               config.setExposedHeaders(Arrays.asList(exposedHeaders));
            }
//          允许的凭证
            if (mapping.hasAttribute("allow-credentials")) {
               config.setAllowCredentials(Boolean.parseBoolean(mapping.getAttribute("allow-credentials")));
            }
            if (mapping.hasAttribute("max-age")) {
               config.setMaxAge(Long.parseLong(mapping.getAttribute("max-age")));
            }
            corsConfigurations.put(mapping.getAttribute("path"), config.applyPermitDefaultValues());
         }
      }

进入到这个方法org.springframework.web.cors.CorsConfiguration#applyPermitDefaultValues

public CorsConfiguration applyPermitDefaultValues() {
   if (this.allowedOrigins == null) {
      this.addAllowedOrigin(ALL);
   }
   if (this.allowedMethods == null) {
      this.setAllowedMethods(Arrays.asList(
            HttpMethod.GET.name(), HttpMethod.HEAD.name(), HttpMethod.POST.name()));
   }
   if (this.allowedHeaders == null) {
      this.addAllowedHeader(ALL);
   }
   if (this.allowCredentials == null) {
      this.setAllowCredentials(true);
   }
   if (this.maxAge == null) {
      this.setMaxAge(1800L);
   }
   return this;
}

进入到这个方法org.springframework.web.servlet.config.MvcNamespaceUtils#registerCorsConfigurations

public static RuntimeBeanReference registerCorsConfigurations(
         Map<String, CorsConfiguration> corsConfigurations, ParserContext context, Object source) {

//    mvcCorsConfigurations 跨域支持bean定义解析
      if (!context.getRegistry().containsBeanDefinition(CORS_CONFIGURATION_BEAN_NAME)) {
         RootBeanDefinition corsDef = new RootBeanDefinition(LinkedHashMap.class);
         corsDef.setSource(source);
         corsDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
         if (corsConfigurations != null) {
            corsDef.getConstructorArgumentValues().addIndexedArgumentValue(0, corsConfigurations);
         }
//       注册mvcCorsConfigurations bean定义
         context.getReaderContext().getRegistry().registerBeanDefinition(CORS_CONFIGURATION_BEAN_NAME, corsDef);
         context.registerComponent(new BeanComponentDefinition(corsDef, CORS_CONFIGURATION_BEAN_NAME));
      }
      else if (corsConfigurations != null) {
         BeanDefinition corsDef = context.getRegistry().getBeanDefinition(CORS_CONFIGURATION_BEAN_NAME);
         corsDef.getConstructorArgumentValues().addIndexedArgumentValue(0, corsConfigurations);
      }
      return new RuntimeBeanReference(CORS_CONFIGURATION_BEAN_NAME);
   }

往上返回到这个方法org.springframework.web.servlet.config.CorsBeanDefinitionParser#parse

说到最后

本次源码解析仅代表个人观点,仅供参考。

03-19 17:03