SpringMVC DispatcherServlet源码(6) 完结 静态资源原理
阅读源码,分析静态资源处理器相关组件:
- 使用SimpleUrlHandlerMapping管理url -> 处理器映射关系
- spring mvc使用WebMvcConfigurationSupport注入SimpleUrlHandlerMapping组件
- DelegatingWebMvcConfiguration可以使用WebMvcConfigurer的配置静态资源url pattern
- spring boot使用EnableWebMvcConfiguration类读取配置参数,然后ResourceHandlerRegistry添加静态资源url pattern
- SimpleUrlHandlerMapping中封装ResourceHttpRequestHandler对象作为请求处理器
- HttpRequestHandlerAdapter支持HttpRequestHandler类型的请求处理器
本文将对上述6点内容展开分析。
注入HandlerMapping
WebMvcConfigurationSupport注入SimpleUrlHandlerMapping组件
在spring mvc中,静态资源也使用HandlerMapping管理映射关系,只是使用的实现类不一样:
- 业务请求使用的HandlerMapping实现类是RequestMappingHandlerMapping类
- 静态资源使用的HandlerMapping实现类是SimpleUrlHandlerMapping类
注入SimpleUrlHandlerMapping对象的入口在WebMvcConfigurationSupport的resourceHandlerMapping方法中:
// Return a handler mapping ordered at Integer.MAX_VALUE-1 with mapped resource handlers.
// To configure resource handling, override addResourceHandlers.
@Bean
public HandlerMapping resourceHandlerMapping(@Qualifier("mvcUrlPathHelper") UrlPathHelper urlPathHelper,@Qualifier("mvcPathMatcher") PathMatcher pathMatcher,@Qualifier("mvcContentNegotiationManager") ContentNegotiationManager contentNegotiationManager,@Qualifier("mvcConversionService") FormattingConversionService conversionService,@Qualifier("mvcResourceUrlProvider") ResourceUrlProvider resourceUrlProvider) {ResourceHandlerRegistry registry = new ResourceHandlerRegistry(this.applicationContext,this.servletContext, contentNegotiationManager, urlPathHelper);// Add resource handlers for serving static resources// 这是一个抽象方法,用于向registry添加静态资源路径pattern// * 一个是spring mvc的DelegatingWebMvcConfiguration类// * 一个是spring boot的WebMvcAutoConfiguration.EnableWebMvcConfiguration类// * 两者的本质就是使用registry.addResourceHandler添加静态资源路径patternaddResourceHandlers(registry);// 根据添加的静态资源路径pattern创建HandlerMapping// 里面创建的是SimpleUrlHandlerMapping类型对象AbstractHandlerMapping handlerMapping = registry.getHandlerMapping();if (handlerMapping == null) {return null;}handlerMapping.setPathMatcher(pathMatcher);handlerMapping.setUrlPathHelper(urlPathHelper);handlerMapping.setInterceptors(getInterceptors(conversionService, resourceUrlProvider));handlerMapping.setCorsConfigurations(getCorsConfigurations());return handlerMapping;
}
下文将介绍:
- addResourceHandlers的实现
- registry创建SimpleUrlHandlerMapping的方式
DelegatingWebMvcConfiguration的addResourceHandlers方法
protected void addResourceHandlers(ResourceHandlerRegistry registry) {this.configurers.addResourceHandlers(registry);
}
configurers是WebMvcConfigurerComposite对象,内部封装这容器里面的所有WebMvcConfigurer组件集:
private final WebMvcConfigurerComposite configurers = new WebMvcConfigurerComposite();@Autowired(required = false)
public void setConfigurers(List<WebMvcConfigurer> configurers) {if (!CollectionUtils.isEmpty(configurers)) {this.configurers.addWebMvcConfigurers(configurers);}
}
当调用this.configurers.addResourceHandlers时,WebMvcConfigurerComposite又会通过WebMvcConfigurer添加静态资源路径pattern:
public void addResourceHandlers(ResourceHandlerRegistry registry) {for (WebMvcConfigurer delegate : this.delegates) {// 这里通过WebMvcConfigurer调用扩展逻辑,添加静态资源路径patterndelegate.addResourceHandlers(registry);}
}
例如:
@Component
public class AppConfig implements WebMvcConfigurer {// ...@Overridepublic void addResourceHandlers(ResourceHandlerRegistry registry) {registry.addResourceHandler("/static/**").addResourceLocations("/static/");}// ...
}
EnableWebMvcConfiguration的addResourceHandlers方法
protected void addResourceHandlers(ResourceHandlerRegistry registry) {// 调用父类方法,也就是使用WebMvcConfigurer添加静态资源patternsuper.addResourceHandlers(registry);if (!this.resourceProperties.isAddMappings()) {return;}addResourceHandler(registry, "/webjars/**", "classpath:/META-INF/resources/webjars/");// spring boot的spring.mvc.staticPathPattern配置参数// spring boot的spring.resources.staticLocations配置参数addResourceHandler(registry, this.mvcProperties.getStaticPathPattern(),this.resourceProperties.getStaticLocations());
}private void addResourceHandler(ResourceHandlerRegistry registry, String pattern, String... locations) {if (registry.hasMappingForPattern(pattern)) {return;}// 添加静态资源patternResourceHandlerRegistration registration = registry.addResourceHandler(pattern);registration.addResourceLocations(locations);registration.setCachePeriod(getSeconds(this.resourceProperties.getCache().getPeriod()));registration.setCacheControl(this.resourceProperties.getCache().getCachecontrol().toHttpCacheControl());customizeResourceHandlerRegistration(registration);this.autoConfiguredResourceHandlers.add(pattern);
}
WebMvcConfigurer接口
定义callback方法,Spring MVC通过这些方法扩展组件:
public interface WebMvcConfigurer {// 配置PathMatchConfigurerdefault void configurePathMatch(PathMatchConfigurer configurer) {}// Configure content negotiation optionsdefault void configureContentNegotiation(ContentNegotiationConfigurer configurer) {}// Configure asynchronous request handling optionsdefault void configureAsyncSupport(AsyncSupportConfigurer configurer) {}// 配置DefaultServletHttpRequestHandlerdefault void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {}// Add Converters and Formatters in addition to the ones registered by defaultdefault void addFormatters(FormatterRegistry registry) {}// 添加拦截器default void addInterceptors(InterceptorRegistry registry) {}// 添加静态资源处理器default void addResourceHandlers(ResourceHandlerRegistry registry) {}// cors配置default void addCorsMappings(CorsRegistry registry) {}// 添加ViewControllerdefault void addViewControllers(ViewControllerRegistry registry) {}// 配置ViewResolverdefault void configureViewResolvers(ViewResolverRegistry registry) {}// 添加参数解析器default void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {}// 添加返回值处理器default void addReturnValueHandlers(List<HandlerMethodReturnValueHandler> handlers) {}// 配置消息转换器default void configureMessageConverters(List<HttpMessageConverter<?>> converters) {}// 扩展消息转换器default void extendMessageConverters(List<HttpMessageConverter<?>> converters) {}// 配置异常处理器default void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {}// 扩展异常处理器default void extendHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {}
}
创建SimpleUrlHandlerMapping对象
protected AbstractHandlerMapping getHandlerMapping() {Map<String, HttpRequestHandler> urlMap = new LinkedHashMap<>();for (ResourceHandlerRegistration registration : this.registrations) {for (String pathPattern : registration.getPathPatterns()) {// * 请注意这里使用的是ResourceHttpRequestHandlerResourceHttpRequestHandler handler = registration.getRequestHandler();if (this.pathHelper != null) {handler.setUrlPathHelper(this.pathHelper);}if (this.contentNegotiationManager != null) {handler.setContentNegotiationManager(this.contentNegotiationManager);}handler.setServletContext(this.servletContext);handler.setApplicationContext(this.applicationContext);try {handler.afterPropertiesSet();} catch (Throwable ex) {throw new BeanInitializationException("Failed to init ResourceHttpRequestHandler", ex);}urlMap.put(pathPattern, handler);}}// 创建SimpleUrlHandlerMappingreturn new SimpleUrlHandlerMapping(urlMap, this.order);
}
SimpleUrlHandlerMapping类
private final Map<String, Object> handlerMap = new LinkedHashMap<>();
使用一个Map<String, Object>管理url pattern -> 处理器对象的映射关系。
从上文可以知道,静态资源映射使用的是ResourceHttpRequestHandler类型的处理器。
ResourceHttpRequestHandler类
这个类实现了HttpRequestHandler接口:
@FunctionalInterface
public interface HttpRequestHandler {void handleRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException;
}
ResourceHttpRequestHandler的代码实现:
public void handleRequest(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException {Resource resource = getResource(request);if (resource == null) {// 404response.sendError(HttpServletResponse.SC_NOT_FOUND);return;}if (HttpMethod.OPTIONS.matches(request.getMethod())) {response.setHeader("Allow", getAllowHeader());return;}// Supported methods and required sessioncheckRequest(request);// Header phaseif (new ServletWebRequest(request, response).checkNotModified(resource.lastModified())) {return;}// Apply cache settings, if anyprepareResponse(response);// Check the media type for the resourceMediaType mediaType = getMediaType(request, resource);setHeaders(response, resource, mediaType);// Content phaseServletServerHttpResponse outputMessage = new ServletServerHttpResponse(response);// 不是range请求if (request.getHeader(HttpHeaders.RANGE) == null) {// 把资源写出去this.resourceHttpMessageConverter.write(resource, mediaType, outputMessage);} else {ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(request);try {// range请求List<HttpRange> httpRanges = inputMessage.getHeaders().getRange();response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT);// 把资源写出去this.resourceRegionHttpMessageConverter.write(HttpRange.toResourceRegions(httpRanges, resource), mediaType, outputMessage);} catch (IllegalArgumentException ex) {response.setHeader(HttpHeaders.CONTENT_RANGE, "bytes */" + resource.contentLength());response.sendError(HttpServletResponse.SC_REQUESTED_RANGE_NOT_SATISFIABLE);}}
}
HttpRequestHandlerAdapter类
前面的文章已经介绍,HttpRequestHandlerAdapter负责处理HttpRequestHandler类型的处理器:
public class HttpRequestHandlerAdapter implements HandlerAdapter {@Overridepublic boolean supports(Object handler) {return (handler instanceof HttpRequestHandler);}@Override@Nullablepublic ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {((HttpRequestHandler) handler).handleRequest(request, response);return null;}@Overridepublic long getLastModified(HttpServletRequest request, Object handler) {if (handler instanceof LastModified) {return ((LastModified) handler).getLastModified(request);}return -1L;}
}
这个组件在WebMvcConfigurationSupport的httpRequestHandlerAdapter方法注入。
小结
至此,我们用了6篇文章详细介绍了SpringMVC DispatcherServlet的注册、请求转发、消息转换等内容,DispatcherServlet的源码分析到此可以结束了。
相关文章:
SpringMVC DispatcherServlet源码(6) 完结 静态资源原理
阅读源码,分析静态资源处理器相关组件: 使用SimpleUrlHandlerMapping管理url -> 处理器映射关系spring mvc使用WebMvcConfigurationSupport注入SimpleUrlHandlerMapping组件DelegatingWebMvcConfiguration可以使用WebMvcConfigurer的配置静态资源url…...
2023年全国最新会计专业技术资格精选真题及答案9
百分百题库提供会计专业技术资格考试试题、会计考试预测题、会计专业技术资格考试真题、会计证考试题库等,提供在线做题刷题,在线模拟考试,助你考试轻松过关。 四、材料题 1.某企业为增值税一般纳税人,2019年12月初“应付职工薪酬…...
Web3中文|把Web3装进口袋,Solana手机Saga有何魔力?
2月23日,Solana Web3手机Saga发布新的消息,将推出NFT铸造应用程序Minty Fresh。在Minty Fresh,用户仅需轻点并完成拍摄,就可以直接在手机中进行NFT铸造,并在几秒钟内将其转换为链上NFT,NFT还可以发布在 Ins…...
【配电网优化】基于串行和并行ADMM算法的配电网优化研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
数据结构初阶 -- 顺序表
数据结构初阶 链表的讲解 目录 一. 线性表 1.1 定义 1.2 特点 二. 顺序表 2.1 定义 2.2 代码 2.3 功能需求 2.4 静态顺序表的特点以及缺点 2.5 动态的顺序表 2.6 动态顺序表接口的实现 三. 代码 头文件 主文件 一. 线性表 1.1 定义 线性表(linear li…...
uniapp:3分钟搞定在线推送uni.createPushMessage,uni.onPushMessage
安卓端 在线推送功能演示: 1、dcloud后台申请开通uniPush dcloud后台 (1):找到我的应用 (2):点进去后,各平台信息,点击新增 (3):填…...
C/C++开发,无可避免的多线程(篇一).跨平台并行编程姗姗来迟
一、编译环境准备 在正式进入c/c多线程编程系列之前,先来搭建支持多线程编译的编译环境。 1.1 MinGW(win) 进入Downloads - MinGW-w64下载页面,选择MinGW-w64-builds跳转下载, 再次进行跳转: 然后进入下载页…...
如何把照片的底色修改为想要的颜色
如何给照片更换底色?其实有可以一键给照片更换底色的 APP ,但是几乎都要收费。如果想要免费的给照片更换底色的话,分享两种简单便捷的方法给你。掌握了这项技能,以后就不用店花钱处理啦!1、免费!线上快速 给…...
【高效办公】批量生成固定模板的文件夹名称
老师让你按照他的要求生成每位学生的文件夹,你是学委,让你马上完成该任务,但你又不想是手动一个一个码字,因此聪明的你就看到了本篇文章啦!!! 虽说一个人懒惰,并不是好的事情。 但这个似乎合情合理啊~ 然后,就动手想办法,一开始就真的打算码字了。。 思路 在实际开…...
redis的集群方式
1.主从复制 主从复制原理: 从服务器连接主服务器,发送SYNC命令; 主服务器接收到SYNC命名后,开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所有写命令; 主服务器BGSAVE执行完后,向所有从服务…...
温控负荷的需求响应潜力评估及其协同优化管理研究(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
模电学习9. MOS管使用入门
模电学习9. MOS管使用入门一、mos管理简介1. 简介2. mos管理的特点3. MOS管的工作状态(1)放大功能(2)截止区(3)饱和区3. Mos管的分类(1)按照工作模式分类:(2&…...
【算法】【数组与矩阵模块】正数组中累加和为给定值的最长子数组长度,空间复杂度O(1)解法
目录前言问题介绍解决方案代码编写java语言版本c语言版本c语言版本思考感悟写在最后前言 当前所有算法都使用测试用例运行过,但是不保证100%的测试用例,如果存在问题务必联系批评指正~ 在此感谢左大神让我对算法有了新的感悟认识! 问题介绍 …...
3.1.2 创建表
文章目录1.创建表2.表创建基础3.表的主键4.使用null值5.使用AUTO_INCREMENT6.指定默认值7. 字段备注8.引擎类型9.外键1.创建表 表的创建一般有俩种方式,一种是使用交互式创建和管理表的工具,比如我们安装的MariaDB,另一种是使用MySQL 语句进…...
使用netlify实现自动化部署前端项目(无服务器版本)
介绍 本文以 github仓库进行介绍关联netlify的无服务前端自动化部署。用途:个人网站设计、小游戏等当然这只是让你入门~具体细节等待你自己去探索 实现 打开官方网站 如果没有注册过的账户,你需要使用 github 去进行登录。注册完成后会自动给你提示填…...
MATLAB点云数据处理(二十九):可视化点云之pcshow参数详解与快捷键操作
文章目录 1 pcshow简述2 最简单的pcshow3 带参数的pcshow3.1 点大小参数----MakerSize3.2 背景色参数----Background3.3 指定竖直轴参数----VerticalAxis3.4 指定垂直轴方向参数----VerticalAxisDir3.5 投影参数----Projection3.6 指定可视化平面参数----ViewPlane3.7 颜色渲染…...
顺序表——重置版
本期我们来实现数据结构的顺序表(这个之前写过一次,不过本期和之前可能会略有不同,但大体相同),大家可以看一下我们之前完成的顺序表 (6条消息) 顺序表及其多种接口的实现_顺序表类中实现接口方法_KLZUQ的博客-CSDN博客…...
PyQt5自然语言处理入门案例笔记
前言 最近想将自然语言处理的项目进行可视化,尽量还是使用回Python语言,因此打算用PyQt来实现相应的功能。 入门案例 一个简单的自然语言处理的demo,使用PyQt框架,该demo可以读取文本文件,对文件中的文本进行情感分…...
使用 CSS 替换表行颜色?
跳到主内容 我正在使用一个带有交替行颜色的表格。 tr.d0 td {background-color: #CC9999;color: black; } tr.d1 td {background-color: #9999CC;color: black; }<table><tr class"d0"><td>One</td><td>one</td></tr>&…...
智能家居控制系统
🥁作者: 华丞臧. 📕专栏:【项目经验】 各位读者老爷如果觉得博主写的不错,请诸位多多支持(点赞收藏关注)。如果有错误的地方,欢迎在评论区指出。 推荐一款刷题网站 👉 LeetCode刷题网站…...
ReadCat小说阅读器完整指南:如何打造纯净无干扰的数字阅读空间
ReadCat小说阅读器完整指南:如何打造纯净无干扰的数字阅读空间 【免费下载链接】read-cat 一款免费、开源、简洁、纯净、无广告的小说阅读器 项目地址: https://gitcode.com/gh_mirrors/re/read-cat 在数字阅读日益普及的今天,广告弹窗、付费订阅…...
如何快速为OpenWrt路由器安装Turbo ACC网络加速:终极性能优化指南
如何快速为OpenWrt路由器安装Turbo ACC网络加速:终极性能优化指南 【免费下载链接】turboacc 一个适用于官方openwrt(22.03/23.05/24.10) firewall4的turboacc 项目地址: https://gitcode.com/gh_mirrors/tu/turboacc 还在为路由器卡顿、网络延迟而烦恼吗&am…...
如何通过Whisky在macOS上实现Windows程序无缝运行?4步技术实践指南
如何通过Whisky在macOS上实现Windows程序无缝运行?4步技术实践指南 【免费下载链接】Whisky A modern Wine wrapper for macOS built with SwiftUI 项目地址: https://gitcode.com/gh_mirrors/wh/Whisky 对于macOS开发者而言,运行Windows专用软件…...
QRazyBox终极指南:5步快速修复损坏的二维码
QRazyBox终极指南:5步快速修复损坏的二维码 【免费下载链接】qrazybox QR Code Analysis and Recovery Toolkit 项目地址: https://gitcode.com/gh_mirrors/qr/qrazybox 你是否曾经遇到过无法扫描的二维码?那些因打印模糊、屏幕损坏或污渍覆盖而失…...
告别纯前端‘假识别’:UniApp+微信小程序如何实现真·人脸检测与姿态校验
告别纯前端‘假识别’:UniApp微信小程序如何实现真人脸检测与姿态校验 在移动应用开发中,人脸识别功能已经从单纯的"拍照上传"进化到了需要实时验证用户真实性的阶段。许多开发者可能遇到过这样的尴尬:用户上传的照片明明不符合要求…...
Visual C++运行库终极解决方案:告别DLL缺失烦恼的快速指南
Visual C运行库终极解决方案:告别DLL缺失烦恼的快速指南 【免费下载链接】vcredist AIO Repack for latest Microsoft Visual C Redistributable Runtimes 项目地址: https://gitcode.com/gh_mirrors/vc/vcredist 你是否曾在打开某个软件或游戏时,…...
高效一键解锁12种加密音乐:Unlock Music免费开源工具完全指南
高效一键解锁12种加密音乐:Unlock Music免费开源工具完全指南 【免费下载链接】unlock-music 在浏览器中解锁加密的音乐文件。原仓库: 1. https://github.com/unlock-music/unlock-music ;2. https://git.unlock-music.dev/um/web 项目地址…...
终极Python代码混淆指南:保护敏感逻辑的7个实用方法
终极Python代码混淆指南:保护敏感逻辑的7个实用方法 【免费下载链接】python-mastery Advanced Python Mastery (course by dabeaz) 项目地址: https://gitcode.com/gh_mirrors/py/python-mastery GitHub 加速计划 / py / python-mastery项目是 Advanced Pyt…...
Python金融数据获取终极指南:3分钟掌握同花顺问财数据采集
Python金融数据获取终极指南:3分钟掌握同花顺问财数据采集 【免费下载链接】pywencai 获取同花顺问财数据 项目地址: https://gitcode.com/gh_mirrors/py/pywencai 想要快速获取同花顺问财的金融数据吗?pywencai是你需要了解的终极Python工具&…...
PRML马尔可夫链:HMM在序列预测中的终极应用指南
PRML马尔可夫链:HMM在序列预测中的终极应用指南 【免费下载链接】PRML PRML algorithms implemented in Python 项目地址: https://gitcode.com/gh_mirrors/pr/PRML PRML项目为机器学习爱好者提供了Christopher Bishop经典著作《模式识别与机器学习》的完整P…...
