SpringMVC源码情操陶冶-ResourcesBeanDefinitionParser静态资源解析器
2017-06-26 17:52
471 查看
解析mvc:resources节点,控制对静态资源的映射访问
查看官方注释
/** * {@link org.springframework.beans.factory.xml.BeanDefinitionParser} that parses a * {@code resources} element to register a {@link ResourceHttpRequestHandler} and * register a {@link SimpleUrlHandlerMapping} for mapping resource requests, * and a {@link HttpRequestHandlerAdapter}. Will also create a resource handling * chain with {@link ResourceResolver}s and {@link ResourceTransformer}s. * * @author Keith Donald * @author Jeremy Grelle * @author Brian Clozel * @since 3.0.4 */
根据注释我们得知该解析器的作用是将
mvc:resources节点解析为
ResourceHttpRequestHandler/SimpleUrlHandlerMapping-匹配mapping属性对应的访问请求
HttpRequestHandlerAdapter-http请求适配器
ResourceResolver/ResourceTransformer-访问的资源查询处理器,针对于location属性
ResourcesBeanDefinitionParser#parse()-解析逻辑
解析涉及的内容偏多,得多花点小心思,源码如下@Override public BeanDefinition parse(Element element, ParserContext parserContext) { Object source = parserContext.extractSource(element); //注册ResourceUrlProvider对象,主要是设置对每个请求都设置上RESOURCE_URL_PROVIDER_ATTR属性,供获取此对象 //在ResourceResolver中会使用 registerUrlProvider(parserContext, source); //解析location属性,注册为ResourceHttpRequestHandler对象 String resourceHandlerName = registerResourceHandler(parserContext, element, source); if (resourceHandlerName == null) { return null; } //解析mapping属性,注册SimpleUrlHandlerMapping对象 Map<String, String> urlMap = new ManagedMap<String, String>(); String resourceRequestPath = element.getAttribute("mapping"); if (!StringUtils.hasText(resourceRequestPath)) { parserContext.getReaderContext().error("The 'mapping' attribute is required.", parserContext.extractSource(element)); return null; } //mapping对应的值与ResourceHttpRequestHandler匹配 urlMap.put(resourceRequestPath, resourceHandlerName); RuntimeBeanReference pathMatcherRef = MvcNamespaceUtils.registerPathMatcher(null, parserContext, source); RuntimeBeanReference pathHelperRef = MvcNamespaceUtils.registerUrlPathHelper(null, parserContext, source); 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); //order属性-执行顺序,越大优先级越低 String order = element.getAttribute("order"); // Use a default of near-lowest precedence, still allowing for even lower precedence in other mappings handlerMappingDef.getPropertyValues().add("order", StringUtils.hasText(order) ? order : Ordered.LOWEST_PRECEDENCE - 1); //SimpleUrlHandlerMapping添加corsConfigurations属性 RuntimeBeanReference corsConfigurationsRef = MvcNamespaceUtils.registerCorsConfigurations(null, parserContext, source); handlerMappingDef.getPropertyValues().add("corsConfigurations", corsConfigurationsRef); //注册SimpleUrlHandlerMapping到spring bean工厂中 String beanName = parserContext.getReaderContext().generateBeanName(handlerMappingDef); parserContext.getRegistry().registerBeanDefinition(beanName, handlerMappingDef); parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, beanName)); //注册BeanNameUrlHandlerMapping/HttpRequestHandlerAdapter/SimpleControllerHandlerAdapter到bean工厂 MvcNamespaceUtils.registerDefaultComponents(parserContext, source); return null; }
以上主要涉及
location、
mapping属性的解析以及注册默认的bean,下面将从这三块来进行主要的分析
ResourcesBeanDefinitionParser#registerResourceHandler()-解析location属性
简要分析下源码private String registerResourceHandler(ParserContext parserContext, Element element, Object source) { //获取location属性,此属性不可为空 String locationAttr = element.getAttribute("location"); if (!StringUtils.hasText(locationAttr)) { parserContext.getReaderContext().error("The 'location' attribute is required.", parserContext.extractSource(element)); return null; } //支持location多路径和classpath前缀,其中以,分隔 ManagedList<String> locations = new ManagedList<String>(); locations.addAll(Arrays.asList(StringUtils.commaDelimitedListToStringArray(locationAttr))); //创建ResourceHttpRequestHandler bean RootBeanDefinition resourceHandlerDef = new RootBeanDefinition(ResourceHttpRequestHandler.class); resourceHandlerDef.setSource(source); resourceHandlerDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); //添加locations属性 MutablePropertyValues values = resourceHandlerDef.getPropertyValues(); values.add("locations", locations); //添加cacheSeconds属性-cache有效时间 String cacheSeconds = element.getAttribute("cache-period"); if (StringUtils.hasText(cacheSeconds)) { values.add("cacheSeconds", cacheSeconds); } //解析子节点mvc:cache-control cache控制器 Element cacheControlElement = DomUtils.getChildElementByTagName(element, "cache-control"); if (cacheControlElement != null) { CacheControl cacheControl = parseCacheControl(cacheControlElement); values.add("cacheControl", cacheControl); } //解析mvc:resource-chain 包含mvc:resolver/mvc:transformers //对应ResourceHttpRequestHandler#resourceResolvers/resourceTransformers属性 Element resourceChainElement = DomUtils.getChildElementByTagName(element, "resource-chain"); if (resourceChainElement != null) { parseResourceChain(resourceHandlerDef, parserContext, resourceChainElement, source); } //处理请求中的media type Object manager = MvcNamespaceUtils.getContentNegotiationManager(parserContext); if (manager != null) { values.add("contentNegotiationManager", manager); } //注册ResourceHttpRequestHandler String beanName = parserContext.getReaderContext().generateBeanName(resourceHandlerDef); parserContext.getRegistry().registerBeanDefinition(beanName, resourceHandlerDef); parserContext.registerComponent(new BeanComponentDefinition(resourceHandlerDef, beanName)); return beanName; }
注册ResourceHttpRequestHandler,作用是对静态资源的location路径进行保存
其会被
HttpRequestHandlerAdapter通过
handle()方法调用
支持location多路径和classpath前缀,其中以,分隔
默认的resourceResolvers集合只有PathResourceResolver,可通过
mvc:resolver指定,用于静态资源的获取
默认resourceTransformers集合为空,可通过
mvc:transformer指定
mapping属性绑定ResourceHttpRequestHandler资源获取类
Map<String, String> urlMap = new ManagedMap<String, String>(); String resourceRequestPath = element.getAttribute("mapping"); if (!StringUtils.hasText(resourceRequestPath)) { parserContext.getReaderContext().error("The 'mapping' attribute is required.", parserContext.extractSource(element)); return null; } urlMap.put(resourceRequestPath, resourceHandlerName);
源码中只是保存在
urlMap集合中,此为
SimpleUrlHandlerMapping的一个内部属性,所以
SimpleUrlHandlerMapping是最终保存
mvc:resource信息的处理逻辑类
MvcNamespaceUtils.registerDefaultComponents()-默认的组件注册
具体的代码就不展开了,有兴趣的自行去查阅public static void registerDefaultComponents(ParserContext parserContext, Object source) { registerBeanNameUrlHandlerMapping(parserContext, source); registerHttpRequestHandlerAdapter(parserContext, source); registerSimpleControllerHandlerAdapter(parserContext, source); }
小结
注册
ResourceHttpRequestHandler,作用为处理location对应的服务端资源。其中location支持多路径配置,"/"相对于工程根目录,也支持
classpath:前缀
注册
SimpleUrlHandlerMapping处理类,其为
AbstractHandlerMapping的实现类,关注
getHandler()方法,主要供springmvc响应请求调用
SimpleUrlHandlerMapping的内部属性
urlMap,用于关联
mapping配置与
location配置处理器
ResourceHttpRequestHandler
默认会注册
BeanNameUrlHandlerMapping、
HttpRequestHandlerAdapter、
SimpleControllerHandlerAdapter对象,供springmvc调用
mvc:resources最终会注册为SimpleUrlHandlerMapping对象,其处理逻辑是根据请求的路径是否匹配mapping属性指定的ant-style路径,是则通过ResourceHttpRequestHandler解析对应的location获取相应的服务器资源直接响应给客户端
相关文章推荐
- SpringMVC源码情操陶冶-ViewResolver视图解析
- SpringMVC源码情操陶冶-DispatcherServlet
- SpringMVC源码情操陶冶-AbstractHandlerMapping
- Spring源码情操陶冶-自定义节点的解析
- SpringMVC源码情操陶冶-AbstractHandlerExceptionResolver
- SpringMVC源码情操陶冶-RequestMappingHandlerAdapter适配器
- SpringMVC源码情操陶冶-InterceptorsBeanDefinitionParser拦截器解析器
- SpringMVC源码情操陶冶-FreeMarker之web配置
- Spring源码情操陶冶-PathMatchingResourcePatternResolver路径资源匹配溶解器
- Spring源码情操陶冶-PathMatchingResourcePatternResolver路径资源匹配溶解器
- SpringMVC源码情操陶冶-AnnotationDrivenBeanDefinitionParser注解解析器
- SpringMVC源码情操陶冶-View视图渲染
- SpringMVC源码情操陶冶-DispatcherServlet类简析(一)
- Spring源码情操陶冶-AOP之Advice通知类解析与使用
- SpringMVC源码情操陶冶-HandlerAdapter适配器简析
- SpringMVC源码情操陶冶-AbstractHandlerMethodMapping
- SpringMVC源码情操陶冶-DispatcherServlet简析(二)
- SpringMVC源码情操陶冶-AbstractUrlHandlerMapping
- SpringMVC源码情操陶冶-DispatcherServlet父类简析
- SpringMVC源码情操陶冶-FreeMarker之web配置