1. 程式人生 > >springmvc原始碼解析MvcNamespaceHandler之<mvc:resources/>

springmvc原始碼解析MvcNamespaceHandler之<mvc:resources/>

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

說在前面

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

 

springmvc配置解析

本次介紹MvcNamespaceHandler。

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

@Override
   public BeanDefinition parse(Element element, ParserContext context) {
      Object source = context.extractSource(element);
//    註冊url服務處理器 ->
      registerUrlProvider(context, source);
//    註冊路徑匹配器bean定義 ->
      RuntimeBeanReference pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(null, context, source);
//    註冊url路徑匹配器bean定義 ->
      RuntimeBeanReference pathHelperRef = MvcNamespaceUtils.registerUrlPathHelper(null, context, source);
//    註冊resourceHandler ->
      String resourceHandlerName = registerResourceHandler(context, element, pathHelperRef, source);
      if (resourceHandlerName == null) {
         return null;
      }

      Map<String, String> urlMap = new ManagedMap<String, String>();
//    解析對映
      String resourceRequestPath = element.getAttribute("mapping");
      if (!StringUtils.hasText(resourceRequestPath)) {
         context.getReaderContext().error("The 'mapping' attribute is required.", context.extractSource(element));
         return null;
      }
      urlMap.put(resourceRequestPath, resourceHandlerName);
//    註冊SimpleUrlHandlerMapping bean定義
      RootBeanDefinition handlerMappingDef = new RootBeanDefinition(SimpleUrlHandlerMapping.class);
      handlerMappingDef.setSource(source);
      handlerMappingDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
      handlerMappingDef.getPropertyValues().add("urlMap", urlMap);
      handlerMappingDef.getPropertyValues().add("pathMatcher", pathMatcherRef).add("urlPathHelper", pathHelperRef);
//    解析順序屬性
      String orderValue = element.getAttribute("order");
      // Use a default of near-lowest precedence, still allowing for even lower precedence in other mappings
      Object order = StringUtils.hasText(orderValue) ? orderValue : Ordered.LOWEST_PRECEDENCE - 1;
      handlerMappingDef.getPropertyValues().add("order", order);
//    註冊跨域bean支援bean定義 ->
      RuntimeBeanReference corsRef = MvcNamespaceUtils.registerCorsConfigurations(null, context, source);
      handlerMappingDef.getPropertyValues().add("corsConfigurations", corsRef);
      String beanName = context.getReaderContext().generateBeanName(handlerMappingDef);
      context.getRegistry().registerBeanDefinition(beanName, handlerMappingDef);
      context.registerComponent(new BeanComponentDefinition(handlerMappingDef, beanName));
      // Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
      // Register HttpRequestHandlerAdapter 註冊預設元件 ->
      MvcNamespaceUtils.registerDefaultComponents(context, source);
      return null;
   }

進入到這個方法org.springframework.web.servlet.config.ResourcesBeanDefinitionParser#registerUrlProvider

private void registerUrlProvider(ParserContext context, Object source) {
      if (!context.getRegistry().containsBeanDefinition(RESOURCE_URL_PROVIDER)) {
         RootBeanDefinition urlProvider = new RootBeanDefinition(ResourceUrlProvider.class);
         urlProvider.setSource(source);
         urlProvider.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
         context.getRegistry().registerBeanDefinition(RESOURCE_URL_PROVIDER, urlProvider);
//       註冊mvcResourceUrlProvider bean定義
         context.registerComponent(new BeanComponentDefinition(urlProvider, RESOURCE_URL_PROVIDER));
//       註冊ResourceUrlProviderExposingInterceptor bean定義
         RootBeanDefinition interceptor = new RootBeanDefinition(ResourceUrlProviderExposingInterceptor.class);
         interceptor.setSource(source);
         interceptor.getConstructorArgumentValues().addIndexedArgumentValue(0, urlProvider);
//       註冊MappedInterceptor bean定義
         RootBeanDefinition mappedInterceptor = new RootBeanDefinition(MappedInterceptor.class);
         mappedInterceptor.setSource(source);
         mappedInterceptor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
         mappedInterceptor.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
         mappedInterceptor.getConstructorArgumentValues().addIndexedArgumentValue(1, interceptor);
         String mappedInterceptorName = context.getReaderContext().registerWithGeneratedName(mappedInterceptor);
         context.registerComponent(new BeanComponentDefinition(mappedInterceptor, mappedInterceptorName));
      }
   }

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

public static RuntimeBeanReference registerPathMatcher(
         RuntimeBeanReference pathMatcherRef, ParserContext parserContext, Object source) {

      if (pathMatcherRef != null) {
         if (parserContext.getRegistry().isAlias(PATH_MATCHER_BEAN_NAME)) {
            parserContext.getRegistry().removeAlias(PATH_MATCHER_BEAN_NAME);
         }
//       註冊別名mvcPathMatcher
         parserContext.getRegistry().registerAlias(pathMatcherRef.getBeanName(), PATH_MATCHER_BEAN_NAME);
      }
      else if (!parserContext.getRegistry().isAlias(PATH_MATCHER_BEAN_NAME)
            && !parserContext.getRegistry().containsBeanDefinition(PATH_MATCHER_BEAN_NAME)) {
         RootBeanDefinition pathMatcherDef = new RootBeanDefinition(AntPathMatcher.class);
         pathMatcherDef.setSource(source);
         pathMatcherDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//       註冊mvcPathMatcher bean定義
         parserContext.getRegistry().registerBeanDefinition(PATH_MATCHER_BEAN_NAME, pathMatcherDef);
         parserContext.registerComponent(new BeanComponentDefinition(pathMatcherDef, PATH_MATCHER_BEAN_NAME));
      }
      return new RuntimeBeanReference(PATH_MATCHER_BEAN_NAME);
   }

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

public static RuntimeBeanReference registerUrlPathHelper(
         RuntimeBeanReference urlPathHelperRef, ParserContext parserContext, Object source) {

      if (urlPathHelperRef != null) {
         if (parserContext.getRegistry().isAlias(URL_PATH_HELPER_BEAN_NAME)) {
            parserContext.getRegistry().removeAlias(URL_PATH_HELPER_BEAN_NAME);
         }
//       註冊mvcUrlPathHelper別名
         parserContext.getRegistry().registerAlias(urlPathHelperRef.getBeanName(), URL_PATH_HELPER_BEAN_NAME);
      }
      else if (!parserContext.getRegistry().isAlias(URL_PATH_HELPER_BEAN_NAME)
            && !parserContext.getRegistry().containsBeanDefinition(URL_PATH_HELPER_BEAN_NAME)) {
         RootBeanDefinition urlPathHelperDef = new RootBeanDefinition(UrlPathHelper.class);
         urlPathHelperDef.setSource(source);
         urlPathHelperDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
//       註冊mvcUrlPathHelper bean定義
         parserContext.getRegistry().registerBeanDefinition(URL_PATH_HELPER_BEAN_NAME, urlPathHelperDef);
         parserContext.registerComponent(new BeanComponentDefinition(urlPathHelperDef, URL_PATH_HELPER_BEAN_NAME));
      }
      return new RuntimeBeanReference(URL_PATH_HELPER_BEAN_NAME);
   }

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

private String registerResourceHandler(
         ParserContext context, Element element, RuntimeBeanReference pathHelperRef, Object source) {

//    解析location屬性值
      String locationAttr = element.getAttribute("location");
      if (!StringUtils.hasText(locationAttr)) {
         context.getReaderContext().error("The 'location' attribute is required.", context.extractSource(element));
         return null;
      }

//    註冊ResourceHttpRequestHandler bean定義
      RootBeanDefinition resourceHandlerDef = new RootBeanDefinition(ResourceHttpRequestHandler.class);
      resourceHandlerDef.setSource(source);
      resourceHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
      MutablePropertyValues values = resourceHandlerDef.getPropertyValues();
//    解析url路徑解析器
      values.add("urlPathHelper", pathHelperRef);
//    解析路徑值
      values.add("locationValues", StringUtils.commaDelimitedListToStringArray(locationAttr));
//    獲取快取週期
      String cacheSeconds = element.getAttribute("cache-period");
      if (StringUtils.hasText(cacheSeconds)) {
         values.add("cacheSeconds", cacheSeconds);
      }

//    獲取快取配置
      Element cacheControlElement = DomUtils.getChildElementByTagName(element, "cache-control");
      if (cacheControlElement != null) {
//       解析快取配置 ->
         CacheControl cacheControl = parseCacheControl(cacheControlElement);
         values.add("cacheControl", cacheControl);
      }

//    獲取資源域屬性
      Element resourceChainElement = DomUtils.getChildElementByTagName(element, "resource-chain");
      if (resourceChainElement != null) {
//       解析資源域 ->
         parseResourceChain(resourceHandlerDef, context, resourceChainElement, source);
      }

//    獲取媒體型別管理器 ->
      Object manager = MvcNamespaceUtils.getContentNegotiationManager(context);
      if (manager != null) {
         values.add("contentNegotiationManager", manager);
      }

      String beanName = context.getReaderContext().generateBeanName(resourceHandlerDef);
      context.getRegistry().registerBeanDefinition(beanName, resourceHandlerDef);
      context.registerComponent(new BeanComponentDefinition(resourceHandlerDef, beanName));
      return beanName;
   }

進入到這個方法org.springframework.web.servlet.config.ResourcesBeanDefinitionParser#parseResourceChain

private void parseResourceChain(
         RootBeanDefinition resourceHandlerDef, ParserContext context, Element element, Object source) {

      String autoRegistration = element.getAttribute("auto-registration");
      boolean isAutoRegistration = !(StringUtils.hasText(autoRegistration) && "false".equals(autoRegistration));
      ManagedList<Object> resourceResolvers = new ManagedList<Object>();
      resourceResolvers.setSource(source);
      ManagedList<Object> resourceTransformers = new ManagedList<Object>();
      resourceTransformers.setSource(source);
//    解析資源快取 ->
      parseResourceCache(resourceResolvers, resourceTransformers, element, source);
//    解析資源解析轉換器
      parseResourceResolversTransformers(
            isAutoRegistration, resourceResolvers, resourceTransformers, context, element, source);
      if (!resourceResolvers.isEmpty()) {
         resourceHandlerDef.getPropertyValues().add("resourceResolvers", resourceResolvers);
      }
      if (!resourceTransformers.isEmpty()) {
         resourceHandlerDef.getPropertyValues().add("resourceTransformers", resourceTransformers);
      }
   }

進入到這個方法org.springframework.web.servlet.config.ResourcesBeanDefinitionParser#parseResourceCache

private void parseResourceCache(ManagedList<Object> resourceResolvers,
         ManagedList<Object> resourceTransformers, Element element, Object source) {

      String resourceCache = element.getAttribute("resource-cache");
      if ("true".equals(resourceCache)) {
         ConstructorArgumentValues cargs = new ConstructorArgumentValues();
//       註冊CachingResourceResolver bean定義
         RootBeanDefinition cachingResolverDef = new RootBeanDefinition(CachingResourceResolver.class);
         cachingResolverDef.setSource(source);
         cachingResolverDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
         cachingResolverDef.setConstructorArgumentValues(cargs);
//       註冊CachingResourceTransformer bean定義
         RootBeanDefinition cachingTransformerDef = new RootBeanDefinition(CachingResourceTransformer.class);
         cachingTransformerDef.setSource(source);
         cachingTransformerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
         cachingTransformerDef.setConstructorArgumentValues(cargs);
//       獲取快取管理器配置
         String cacheManagerName = element.getAttribute("cache-manager");
         String cacheName = element.getAttribute("cache-name");
         if (StringUtils.hasText(cacheManagerName) && StringUtils.hasText(cacheName)) {
            RuntimeBeanReference cacheManagerRef = new RuntimeBeanReference(cacheManagerName);
            cargs.addIndexedArgumentValue(0, cacheManagerRef);
            cargs.addIndexedArgumentValue(1, cacheName);
         }
         else {
            ConstructorArgumentValues cacheCavs = new ConstructorArgumentValues();
            cacheCavs.addIndexedArgumentValue(0, RESOURCE_CHAIN_CACHE);
//          註冊ConcurrentMapCache bean定義
            RootBeanDefinition cacheDef = new RootBeanDefinition(ConcurrentMapCache.class);
            cacheDef.setSource(source);
            cacheDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
            cacheDef.setConstructorArgumentValues(cacheCavs);
            cargs.addIndexedArgumentValue(0, cacheDef);
         }
         resourceResolvers.add(cachingResolverDef);
         resourceTransformers.add(cachingTransformerDef);
      }
   }

往上返回到這個方法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.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.MvcNamespaceUtils#registerDefaultComponents

public static void registerDefaultComponents(ParserContext parserContext, Object source) {
//    註冊BeanNameUrlHandlerMapping bean定義 ->
      registerBeanNameUrlHandlerMapping(parserContext, source);
//    註冊HttpRequestHandlerAdapter bean定義 ->
      registerHttpRequestHandlerAdapter(parserContext, source);
//    註冊SimpleControllerHandlerAdapter bean定義 ->
      registerSimpleControllerHandlerAdapter(parserContext, source);
//    註冊HandlerMappingIntrospector bean定義 ->
      registerHandlerMappingIntrospector(parserContext, source);
   }

這裡前面解析過了。

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

 

說到最後

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