SpringMVC源码情操陶冶-ResourcesBeanDefinitionParser静态资源解析器
解析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源码情操陶冶-ResourcesBeanDefinitionParser静态资源解析器的更多相关文章
- Spring源码情操陶冶-AnnotationConfigBeanDefinitionParser注解配置解析器
本文承接前文Spring源码情操陶冶-自定义节点的解析,分析spring中的context:annotation-config节点如何被解析 源码概览 对BeanDefinitionParser接口的 ...
- Spring源码情操陶冶-ComponentScanBeanDefinitionParser文件扫描解析器
承接前文Spring源码情操陶冶-自定义节点的解析,本文讲述spring通过context:component-scan节点干了什么事 ComponentScanBeanDefinitionParse ...
- Spring源码情操陶冶-PropertyPlaceholderBeanDefinitionParser注解配置解析器
本文针对spring配置的context:property-placeholder作下简单的分析,承接前文Spring源码情操陶冶-自定义节点的解析 spring配置文件应用 <context: ...
- Spring源码情操陶冶-AOP之ConfigBeanDefinitionParser解析器
aop-Aspect Oriented Programming,面向切面编程.根据百度百科的解释,其通过预编译方式和运行期动态代理实现程序功能的一种技术.主要目的是为了程序间的解耦,常用于日志记录.事 ...
- SpringMVC源码情操陶冶-HandlerAdapter适配器简析
springmvc中对业务的具体处理是通过HandlerAdapter适配器操作的 HandlerAdapter接口方法 列表如下 /** * Given a handler instance, re ...
- Spring源码情操陶冶-自定义节点的解析
本文承接前文Spring源码情操陶冶-DefaultBeanDefinitionDocumentReader#parseBeanDefinitions,特开辟出一块新地来啃啃这块有意思的骨头 自定义节 ...
- SpringMVC源码情操陶冶-FreeMarker之web配置
前言:本文不讲解FreeMarkerView视图的相关配置,其配置基本由FreeMarkerViewResolver实现,具体可参考>>>SpringMVC源码情操陶冶-ViewRe ...
- SpringMVC源码情操陶冶-DispatcherServlet父类简析
阅读源码有助于陶冶情操,本文对springmvc作个简单的向导 springmvc-web.xml配置 <servlet> <servlet-name>dispatch< ...
- SpringMVC源码情操陶冶-DispatcherServlet类简析(一)
阅读源码有利于陶冶情操,此文承接前文SpringMVC源码情操陶冶-DispatcherServlet父类简析 注意:springmvc初始化其他内容,其对应的配置文件已被加载至beanFactory ...
随机推荐
- c++(hash表)
hash表,有时候也被称为散列表.个人认为,hash表是介于链表和二叉树之间的一种中间结构.链表使用十分方便,但是数据查找十分麻烦:二叉树中的数据严格有序,但是这是以多一个指针作为代价的结果.hash ...
- C++输出二进制文件和文本文件
所谓二进制文件和文本文件对于字母而言没有什么不同,都是存储该字母的ASCII码值.能引起不同的是数字和一些排版用符号的格式. 数字在二进制文件中会存储该数字的值,而文本文件中则首先将该数字视为字符量, ...
- [20160711][neven代码移植Windows]
相关说明 neven代码用于人脸检测,该代码是从Android源代码中抽取出来的,可以在Linux系统下通过make命令直接进行编译,并且可以通过代码中opencv目录下的测试文件进行测试. 移植环境 ...
- Spark算子--filter
filter--Transformation类算子 代码示例 result
- dedecms 下载时弹出提示登录框或直接下载
http://jingyan.baidu.com/article/9f63fb918656c2c8400f0ebc.html DEDECMS 默认下载 是直接给出了一个 本地下载的 下载链接 本 ...
- 01 整合IDEA+Maven+SSM框架的高并发的商品秒杀项目之业务分析与DAO层
作者:nnngu 项目源代码:https://github.com/nnngu/nguSeckill 这是一个整合IDEA+Maven+SSM框架的高并发的商品秒杀项目.我们将分为以下几篇文章来进行详 ...
- asp.net -mvc框架复习(7)-基于MVC搭建用户登录项目框架
整体框架: 一.搭建Model层 1.添加通用数据访问类 2.添加实体类(封装和传递数据,和数据库中数据表对应) 3.添加数据访问类(通常和实体类同名,但是后缀名发生改变) 二.搭建控制器层Contr ...
- 在iOS App 中添加启动画面
你可以认为你需要为启动画面编写代码,然而Apple 让你可以非常简单地在Xcode中完成.不需要编写代码,你仅需要在Xcode中进行一些配置. 1.什么是启动画面(Splash Screen)? 启动 ...
- mybatis属性详解
前言 MyBatis是基于"数据库结构不可控"的思想建立的,也就是我们希望数据库遵循第三范式或BCNF,但实际事与愿违,那么结果集映射就是MyBatis为我们提供这种理想与现实间转 ...
- CCF系列之模板生成系统( 201509-3 )
试题名称: 模板生成系统 试题编号: 201509-3 时间限制: 1.0s 内存限制: 256.0MB 问题描述 成成最近在搭建一个网站,其中一些页面的部分内容来自数据库中不同的数据记录,但是页面的 ...