解析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节点解析为

  1. ResourceHttpRequestHandler/SimpleUrlHandlerMapping-匹配mapping属性对应的访问请求
  2. HttpRequestHandlerAdapter-http请求适配器
  3. 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;
}

以上主要涉及locationmapping属性的解析以及注册默认的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路径进行保存

  1. 其会被HttpRequestHandlerAdapter通过handle()方法调用

  2. 支持location多路径和classpath前缀,其中以,分隔

  3. 默认的resourceResolvers集合只有PathResourceResolver,可通过mvc:resolver指定,用于静态资源的获取

  4. 默认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);
}

小结

  1. 注册ResourceHttpRequestHandler,作用为处理location对应的服务端资源。其中location支持多路径配置,"/"相对于工程根目录,也支持classpath:前缀

  2. 注册SimpleUrlHandlerMapping处理类,其为AbstractHandlerMapping的实现类,关注getHandler()方法,主要供springmvc响应请求调用

  3. SimpleUrlHandlerMapping的内部属性urlMap,用于关联mapping配置与location配置处理器ResourceHttpRequestHandler

  4. 默认会注册BeanNameUrlHandlerMappingHttpRequestHandlerAdapterSimpleControllerHandlerAdapter对象,供springmvc调用

  5. mvc:resources最终会注册为SimpleUrlHandlerMapping对象,其处理逻辑是根据请求的路径是否匹配mapping属性指定的ant-style路径,是则通过ResourceHttpRequestHandler解析对应的location获取相应的服务器资源直接响应给客户端

SpringMVC源码情操陶冶-ResourcesBeanDefinitionParser静态资源解析器的更多相关文章

  1. Spring源码情操陶冶-AnnotationConfigBeanDefinitionParser注解配置解析器

    本文承接前文Spring源码情操陶冶-自定义节点的解析,分析spring中的context:annotation-config节点如何被解析 源码概览 对BeanDefinitionParser接口的 ...

  2. Spring源码情操陶冶-ComponentScanBeanDefinitionParser文件扫描解析器

    承接前文Spring源码情操陶冶-自定义节点的解析,本文讲述spring通过context:component-scan节点干了什么事 ComponentScanBeanDefinitionParse ...

  3. Spring源码情操陶冶-PropertyPlaceholderBeanDefinitionParser注解配置解析器

    本文针对spring配置的context:property-placeholder作下简单的分析,承接前文Spring源码情操陶冶-自定义节点的解析 spring配置文件应用 <context: ...

  4. Spring源码情操陶冶-AOP之ConfigBeanDefinitionParser解析器

    aop-Aspect Oriented Programming,面向切面编程.根据百度百科的解释,其通过预编译方式和运行期动态代理实现程序功能的一种技术.主要目的是为了程序间的解耦,常用于日志记录.事 ...

  5. SpringMVC源码情操陶冶-HandlerAdapter适配器简析

    springmvc中对业务的具体处理是通过HandlerAdapter适配器操作的 HandlerAdapter接口方法 列表如下 /** * Given a handler instance, re ...

  6. Spring源码情操陶冶-自定义节点的解析

    本文承接前文Spring源码情操陶冶-DefaultBeanDefinitionDocumentReader#parseBeanDefinitions,特开辟出一块新地来啃啃这块有意思的骨头 自定义节 ...

  7. SpringMVC源码情操陶冶-FreeMarker之web配置

    前言:本文不讲解FreeMarkerView视图的相关配置,其配置基本由FreeMarkerViewResolver实现,具体可参考>>>SpringMVC源码情操陶冶-ViewRe ...

  8. SpringMVC源码情操陶冶-DispatcherServlet父类简析

    阅读源码有助于陶冶情操,本文对springmvc作个简单的向导 springmvc-web.xml配置 <servlet> <servlet-name>dispatch< ...

  9. SpringMVC源码情操陶冶-DispatcherServlet类简析(一)

    阅读源码有利于陶冶情操,此文承接前文SpringMVC源码情操陶冶-DispatcherServlet父类简析 注意:springmvc初始化其他内容,其对应的配置文件已被加载至beanFactory ...

随机推荐

  1. COGS 862. 二进制数01串【dp+经典二分+字符串】

    862. 二进制数01串 ★   输入文件:kimbits.in   输出文件:kimbits.out   简单对比 时间限制:1 s   内存限制:128 MB USACO/kimbits(译 by ...

  2. Centos/Rhel7部署Zabbix监控(部署篇之服务器篇)

    Zabbix是一个基于WEB界面的提供分布式系统监视以及网络监视功能的企业级的开源解决方案. Zabbix能监视各种网络参数,保证服务器系统的安全运营:并提供灵活的通知机制以让系统管理员快速定位/解决 ...

  3. Spark入门学习

    1. Spark Overview(spark概述) Apache spark是一个快速和通用的集群计算系统.它提供了Java,Scala,Python和R的高级APIs,以及支持通用执行图的优化引擎 ...

  4. event.target与event.srcElement

    target 事件属性可返回事件的目标节点(触发该事件的节点),如生成事件的元素.文档或窗口. 在标准浏览器下我们一般使用event.target就能解决,然而低版本IE浏览器总是会出些幺蛾子,这时候 ...

  5. base64是啥原理

    Base64是一种基于64个可打印字符来表示二进制数据的表示方法.由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符.三个字节有24个比特,对应于4个Base64单元,即3个字节可表 ...

  6. Composer 是什么

    简单来说,Composer 是一个新的安装包管理工具,服务于 PHP 生态系统.它实际上包含了两个部分:Composer 和 Packagist.下面我们就简单说一下他们各自的用途. Composer ...

  7. SQLite 链接大全

    http://www.cnblogs.com/stephen-liu74/archive/2012/01/22/2328757.html

  8. myeclipse编码

    window --->perferences

  9. 开源三维地球GIS引擎Cesium常用功能的开发

    Cesium是一个非常优秀的三维地球GIS引擎(开源且免费).能够加载各种符合标准的地图图层,瓦片图.矢量图等都支持.支持3DMax等建模软件生成的obj文件,支持通用的GIS计算:支持DEM高程图. ...

  10. u8g2库的相关资料

    2017-12-1309:13:32更新51论坛上的帖子,大神自己写的库文件,待调试! http://www.51hei.com/bbs/forum.php?mod=viewthread&ti ...