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 ...
随机推荐
- BZOJ 1207: [HNOI2004]打鼹鼠【妥妥的n^2爆搜,dp】
1207: [HNOI2004]打鼹鼠 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 3259 Solved: 1564[Submit][Statu ...
- [bzoj1999]树网的核
从下午坑到网上..noip的数据太弱,若干的地方写挂结果还随便过= = 最坑的就是网上有些题解没考虑周全... 第一步是找直径,用两次bfs(或者dfs,Linux下系统栈挺大的..)解决.找出其中一 ...
- poj_2528Mayor's posters(线段树)
poj_2528Mayor's posters(线段树) 标签: 线段树 题目连接 Mayor's posters Time Limit: 1000MS Memory Limit: 65536K To ...
- Monthly update for Dynamics 365 for Operation
日期 标题, 类别 版本 描述 2017/8/22 Dyn 365 Fin and Ops, Ent ed July 2017 Plat Update 10 Category: Download ...
- [学习OpenCV攻略][009][从摄像机读入数据]
cvCreateCameraCapture(设备ID) 创建一个摄像机视频,返回值是CvCapture*类型.设备ID表示设备的编号,如果有多个摄像机设备,-1表示随机选择一个设备. #include ...
- putty怎么用?如何使用Putty远程管理Linux主机
Putty是一个免费的Windows 32平台下用于telnet.rlogin和ssh客户端的远程客户端工具,可以通过PUTTY快速的实现SSH连接linux等主机,下面小编就给大家演示一下如何使用P ...
- 2.移植3.4内核-使内核支持烧写yaffs2
在上章-制作文件系统,并使内核成功启动jffs2文件系统了 本章便开始使内核支持烧写yaffs2文件系统 1.首先获取yaffs2源码(参考git命令使用详解) cd /work/nfs_root g ...
- ios开发 第三天
1.复合 对象可以引用其它对象,可以利用其它对象提供的特性. 通过包含作为实例变量的对象指针实现的. 2.OC是单一继承 3.继承-重构 4.类实例化对象时,self指向了对象的首地址. 类对象isa ...
- jstl 的判断使用
JSTL 是JSP的标准标记库 1.必须引入的头部标签 <%@ taglib uri="http://java.sun.com/jstl/core_rt"prefix=&q ...
- 关于JAVA字符编码:Unicode,ISO-8859-1,GBK,UTF-8编码及相互转换
我们最初学习计算机的时候,都学过ASCII编码. 但是为了表示各种各样的语言,在计算机技术的发展过程中,逐渐出现了很多不同标准的编码格式, 重要的有Unicode.UTF.ISO-8859-1和中国人 ...