【新姿势】SpringBoot下时间配置新方式(同文件大小)

SpringBoot + Duration

背景: 在SpringBoot项目中,我们经常需要配置时间参数,作为某一动作的间隔。以往我们通常是在配置文件中定义字段后,直接设置对应的秒或毫秒值,遇到计算时,直接在此基础上做运算。这种方式虽然也能实现基本需求,但不够优美,有时我们更需要5s、4m、3h这样带单位的配置,这种方式更符合我们实际的需要。如果你经常看源码,就会发现SpringBoot中某些内部配置就是使用这种方式,此篇将在源码的基础上对此机制做简要分析。

格式化时间使用的核心是Duration对象

在这里插入图片描述
在实际使用时,我们在配置类中或其它类中定义Duration对象来接收此时间格式配置参数,此类代表时间间隔对象,除自身简单的API外,还可以与JAVA自身的相关事件API结合运算,如LocalDateTime。

LocalDateTime.now().plus([Duration]).atZone(ZoneId.systemDefault()).toInstant().getEpochSecond()

从字符串到Duration,是怎么处理的?有哪些注意事项?

熟悉Spring的话,我们知道框架在解析完类生成对应的BeanDefinition后,会将此类实例化和初始化,如果存在属性操作,会在createBean中调用其populateBean方法完成属性注入,其底层依赖AutowiredAnnotationBeanPostProcessor 等Processor完成此类操作。

public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, BeanFactoryAware {public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) {// 解析得到类中所有@Autowired修饰的变量元数据InjectionMetadata metadata = this.findAutowiringMetadata(beanName, bean.getClass(), pvs);try {// 属性注入操作metadata.inject(bean, beanName, pvs);return pvs;} catch (BeanCreationException var6) {throw var6;} catch (Throwable var7) {throw new BeanCreationException(beanName, "Injection of autowired dependencies failed", var7);}}
}@Nullableprivate Object resolveFieldValue(Field field, Object bean, @Nullable String beanName) {DependencyDescriptor desc = new DependencyDescriptor(field, this.required);desc.setContainingClass(bean.getClass());Set<String> autowiredBeanNames = new LinkedHashSet(1);Assert.state(AutowiredAnnotationBeanPostProcessor.this.beanFactory != null, "No BeanFactory available");TypeConverter typeConverter = AutowiredAnnotationBeanPostProcessor.this.beanFactory.getTypeConverter(); // SimpleTypeConverterObject value;try {// 获取属性值value = AutowiredAnnotationBeanPostProcessor.this.beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter);} catch (BeansException var12) {throw new UnsatisfiedDependencyException((String)null, beanName, new InjectionPoint(field), var12);}*************省略************return value;}}

在ContextAnnotationAutowireCandidateResolver解析类中,根据变量Field对象获取其注解列表,后抽取其具体配置值。

	public Object getSuggestedValue(DependencyDescriptor descriptor) {Object value = this.findValue(descriptor.getAnnotations());if (value == null) {MethodParameter methodParam = descriptor.getMethodParameter();if (methodParam != null) {value = this.findValue(methodParam.getMethodAnnotations());}}return value;}protected Object findValue(Annotation[] annotationsToSearch) {if (annotationsToSearch.length > 0) {AnnotationAttributes attr = AnnotatedElementUtils.getMergedAnnotationAttributes(AnnotatedElementUtils.forAnnotations(annotationsToSearch), this.valueAnnotationType);if (attr != null) {return this.extractValue(attr);}}return null;}protected Object extractValue(AnnotationAttributes attr) {Object value = attr.get("value");if (value == null) {throw new IllegalStateException("Value annotation must have a value attribute");} else {return value;}}

上面说了变量参数解析与值获取的过程,但此时获取的是String对象,需要转换为Duration对象,是调用Duration的静态parse方法吗?
没看源码之前,我以为转换器就是执行此parse方法,但是这里有个问题,parse方法其实仅支持ISO8601标准,使用类似PT15M,我们配置的3M等参数不符合此类标准,直接使用会报错。下面看源码的使用:

	// source即为我们配置的3M// DurationStyle是枚举类,除ISO8601时间格式外,适配了简约模式,也就是我们参数配置的格式DurationStyle.detect(source)// unit可为nullDuration value = style.parse(source, unit);

当把String解析成Duration对象,就可以直接反射完成属性注入了。

InjectedElement element = (InjectedElement)var6.next();
element.inject(target, beanName, pvs);

总结:
1、借助Duration类,实现时间配置值单位的适配,不再被数字值实际单位所困扰
2、Duration实际时间格式有简约版,相比ISO8601更符合我们的使用习惯【具体参考DurationStyle源码】
3、时间格式中,M、H、S、D等单位同时支持大小写,原理是解析正则配置了Pattern.CASE_INSENSITIVE
4、上文简述了注入变量解析的时机、位置及流程

除了时间外,我们还会遇到一个常见配置和其类似,就是文件大小配置,此配置通常配置为字节数,但是我们也可指定单位为:KB、MB、GB等
multipart场景下代码示例:

@ConfigurationProperties(prefix = "spring.servlet.multipart",ignoreUnknownFields = false
)
public class MultipartProperties {private boolean enabled = true;private String location;private DataSize maxFileSize = DataSize.ofMegabytes(1L);private DataSize maxRequestSize = DataSize.ofMegabytes(10L);private DataSize fileSizeThreshold = DataSize.ofBytes(0L);private boolean resolveLazily = false;
}

可以看到各大小指标均被DataSize类型修饰,其parse方法涉及DataUnit枚举类,

public enum DataUnit {BYTES("B", DataSize.ofBytes(1L)),KILOBYTES("KB", DataSize.ofKilobytes(1L)),MEGABYTES("MB", DataSize.ofMegabytes(1L)),GIGABYTES("GB", DataSize.ofGigabytes(1L)),TERABYTES("TB", DataSize.ofTerabytes(1L));
}

在内部转换器的支持下,配置文件中就可配置带单位的大小阈值了。

PS1:和时间Duration封装类不同,DataUnit不支持单位小写,也不支持K、M、G等简写形式,默认单位为字节数
PS2:@MultipartConfig注解和MultipartProperties字段名相同,但类型为基本数据类型,使用此注解不能设置单位

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/289209.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

苏州和数荣获苏州市软件行业协会“杰出贡献理事单位”

2023年12月14日&#xff0c;苏州市软件行业协会第五届第五次理事会议在金螳螂大厦顺利召开。 苏州市工信局副局长万资平&#xff0c;苏州市工信局大数据处处长卢剑荣&#xff0c;苏州市工信局大数据处丁天龙&#xff0c;江苏省软件行业协会副秘书长夏冰莹&#xff0c;苏州市软…

2023美团商家信息

2023美团商家电话、地址、经纬度、评分、均价、执照...

[AutoSar]基础部分 RTE 02 S/R Port 显式/隐式

目录 关键词平台说明一、显式&#xff08;Explicit&#xff09;和隐式&#xff08;Implicit&#xff09;1.1 显式模式1.1.1code 二、隐式模式2.1 code 三、区别 关键词 嵌入式、C语言、autosar、EcuM、Rte 平台说明 项目ValueOSautosar OSautosar厂商vector芯片厂商TI编程语…

ITIL® 4 Foundation​,12月23日即将开课~想了解点击查看

ITIL 4 Foundation即将开课~ 想报名的必须提前预约啦 &#x1f447;&#x1f447;&#x1f447; 培训地点&#xff1a; 远程直播&#xff1a;线上平台学习 开课时间&#xff1a; 周末班&#xff1a;12月23日、24日&#xff1b; 什么是ITIL&#xff1f; 信息技术基础架构…

Gin之GORM事务(转账操作)

禁用默认事务的操作 为了确保数据一致性,GORM 会在事务里执行写入操作(创建、更新、删除)。如果没有这方面的要求,您可以在初始化时禁用它,这将获得大约 30%+ 性能提升。 // 全局禁用 db, err := gorm.Open(sqlite.Open("gorm.db"), &gorm.Config{SkipDef…

高并发神经网络推理部署

高并发的神经网络推理框架部署 highport 是一款封装神经网络推理的高并发的软件架构&#xff0c;已在ESWEEK 2023年皮肤病检测比赛中获得第一名。 这里记录一下highport的软件架构和几个trick优化 软件架构图 解密模块&#xff1a;我们训练完的模型文件是带加密的&#xff0c;…

AOSP 源码编译android 12

目录 一、python安装 a. python2安装 b. python3安装 二、repo管理多个git a.第一步, 新建一个空白文件夹保存repo引导文件,并包含你的路径 b.下载启动器 c.将git-repo中的repo文件复制到 1 创建的.bin目录中 d.修改权限 e. 执行版本检查 三、初始化工程 a.执行创建文件…

【halcon深度学习之那些封装好的库函数】determine_dl_model_detection_param

determine_dl_model_detection_param 目标检测的数据准备过程中的有一个库函数determine_dl_model_detection_param “determine_dl_model_detection_param” 直译为 “确定深度学习模型检测参数”。 这个过程会自动针对给定数据集估算模型的某些高级参数&#xff0c;强烈建议…

[DNS网络] 网页无法打开、显示不全、加载卡顿缓慢 | 解决方案

[网络故障] 网页无法打开、显示不全、加载卡顿缓慢 | 解决方案 问题描述 最近&#xff0c;我在使用CSDN插件浏览 MOOC 网站时&#xff0c;遇到了一些网络故障。具体表现为&#xff1a; MOOC 中国大学慕课网&#xff1a;www.icourse163.org点击CSDN插件首页的 MOOC&#xff08…

实验:使用ADC读取烟雾传感器的值

CubeMX 配置 3.3/4096 * smoke_value 这个表达式的含义是将ADC的原始数值 smoke_valuesmoke_value 转换成相应的电压值&#xff0c;假设ADC的范围是0到4095&#xff0c;电源电压是3.3V。这是一个将ADC的数字值映射到实际电压值的线性转换。 具体来说&#xff1a; 3.33.3 是电…

diffusers-Inpainting

原文链接&#xff1a;添加链接描述 白色mask区域仅使用生成出来的&#xff0c;非白色mask区域使用原始影像&#xff0c;但是图像有点不平滑 import PIL import numpy as np import torchfrom diffusers import AutoPipelineForInpainting from diffusers.utils i…

Linux5.2、进程等待

个人主页&#xff1a;Lei宝啊 愿所有美好如期而遇 目录 进程等待的必要性 进程等待的方法 获取子进程status 进程等待的必要性 首先&#xff0c;子进程退出&#xff0c;如果父进程不去回收子进程资源&#xff0c;读取子进程的PCB&#xff0c;那么就会使子进程变成僵尸进程…