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

news2024/12/23 11:02:29

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);
        }
    }
}


    @Nullable
    private 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(); // SimpleTypeConverter

            Object 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可为null
    Duration 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.coloradmin.cn/o/1326265.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

标准解析|海格里斯HEGERLS四向车调度算法如何解决同层多车车辆路径规划和避让问题?

随着当前各大企业对仓储存储需求的不断攀升&#xff0c;仓储货架业已进入智能自动化系统集成时代&#xff0c;从单一的货架存储已慢慢发展为货架穿梭车提升机拣选系统控制软件仓库管理软件等集成的仓储解决方案&#xff0c;如四向穿梭车系统&#xff0c;多层穿梭车系统&#xf…

解决:OSError: cannot write mode RGBA as JPEG

解决&#xff1a;OSError: cannot write mode RGBA as JPEG 文章目录 解决&#xff1a;OSError: cannot write mode RGBA as JPEG背景报错问题报错翻译报错位置代码报错原因解决方法参考今天的分享就到此结束了 背景 在使用之前的代码时&#xff0c;报错&#xff1a; Traceback…

CodeBlocks配置WinLibs

一、准备工作 1、去Code::Blocks - Browse /Binaries/Nightlies at SourceForge.net下载CodeBlocks最新的nightly build版本&#xff0c;并下载wxWidget dll和Mingw64 dll库文件。 我下载的CB 13411 &#xff0c;Mingw64dlls13.1.0.7z&#xff0c;wxmsw32u_gcc_cb_wx324_2D_g…

​创新驱动,边缘计算领袖:亚马逊云科技海外服务器服务再进化

2022年亚马逊云科技re:Invent盛会于近日在拉斯维加斯成功召开&#xff0c;吸引了众多业界精英和创新者。亚马逊云科技边缘服务副总裁Jan Hofmeyr在演讲中分享了关于亚马逊云科技海外服务器边缘计算的最新发展和创新成果&#xff0c;引发与会者热烈关注。 re:Invent的核心主题是…

从Gitee克隆项目、启动方法

从gitee克隆VUE项目到本地后&#xff0c;不能直接运行&#xff0c;需要进行npm install安装node_modules文件夹里面的内容&#xff0c;因为在git上传的时候&#xff0c;一般都会过滤到node_modules中的依赖文件。 安装依赖以后&#xff0c;启动通过npm run serve启动项目出错。…

MySQL-1

1 数据库基础概念 Data数据 对客观事物的符号表示&#xff0c;如图形符号、数字、字母等&#xff0c;数据是数据库中存储的基本对象。2. DB数据库数据库(Database,简称DB)的定义&#xff1a;“按照数据结构来组织、存储和管理数据的仓库” 3. DBMS数据库管理系统概念&#xff…

多媒体信息化建设,动态数据中心,深入理解分布式系统

目录 一、前言二、双活数据中心三、数据备份方式四、设计双活数据中心需要考虑的问题1、延迟和稳定性2、Quorum/ Tie-Breaker3、工作负载 五、动态数据中心六、深入理解分布式系统1、内容介绍2、作者简介 大家好&#xff0c;我是哪吒。 文末送5本《深入理解分布式系统》 一、…

Amazon Toolkit — CodeWhisperer 使用

tFragment--> 官网&#xff1a;https://aws.amazon.com/cn/codewhisperer/?trkcndc-detail 最近学习了亚马逊云科技的 代码工具&#xff0c;感慨颇多。下面是安装 和使用的分享。 CodeWhisperer&#xff0c;亚马逊推出的实时 AI 编程助手&#xff0c;是一项基于机器学习…

Linux服务器nginx部署Vue前端(详细版)

提示&#xff1a;适用于前后端项目的部署 文章目录 前言一、打包前端文件二、下载和部署Nginx三、配置conf文件启动nginx 前言 搜索到这篇文章想必你已经对Nginx比较了解&#xff0c;我也不对Nginx进行介绍赘述了&#xff0c;只需要明白Nginx本身也是一个静态资源的服务器&…

【MYSQL】MYSQL 的学习教程(三)之索引核心知识点

1. 什么是索引&#xff1f; 索引是一种能提高数据库查询效率的数据结构&#xff0c;一般存储在磁盘的文件中&#xff0c;它是占用物理空间的 适当的索引能提高查询效率&#xff0c;过多的索引会影响数据库表的插入和更新功能。 2. 索引的优劣势 优势&#xff1a; 提高数据…

GEM5 Garent CPU cache消息传递路径:1. NI部分

简介 我们仔细分析下图怎么连的&#xff0c;以及消息传递路径。 图来自https://www.gem5.org/documentation/general_docs/ruby/ 代码的连接 fs.py->ruby.py-> gem5/configs/ruby/MESI_Two_Level.py 中的 create_system( options, full_system, system, dma_ports, b…

STM32单片机项目实例:基于TouchGFX的智能手表设计(7)MVP架构下的交互逻辑设计

STM32单片机项目实例&#xff1a;基于TouchGFX的智能手表设计&#xff08;7&#xff09;MVP架构下的交互逻辑设计 目录 一、概述 二、MVP架构下的交互逻辑 一、概述 本文例程是基于 TouchGFX 的智能手表设计—Designer 软件 UI 设计的例程 0B-2_STM32U575_MVP_Interactive工…

【点选验证码识别】某招标网站反爬虫分析与验证码自动识别

文章目录 1. 写在前面2. 风控描述3. 验证码裁剪4. 验证码识别 【作者主页】&#xff1a;吴秋霖 【作者介绍】&#xff1a;Python领域优质创作者、阿里云博客专家、华为云享专家。长期致力于Python与爬虫领域研究与开发工作&#xff01; 【作者推荐】&#xff1a;对JS逆向感兴趣…

Redis基础篇-002 初识Redis

1、认识NoSQL 1.1 概念 NoSQL是一个非关系型数据库。 常见的NoSQL有&#xff1a;Redis、MongoDB 1.2 NoSQL与SQL的区别 类别SQLNoSQL数据结构结构化非结构化数据关联关联非关联查询方式SQL非SQL事务特性ACIDBASE存储方式磁盘内存扩展性垂直水平使用场景1&#xff09;数据结…

Uniapp + Vue3 封装请求工具挂载全局

新建request.js工具类 const http {// baseUrl 地址baseUrl: http://localhost:8080,// 请求方法request(config) {// config&#xff1a;请求配置对象&#xff0c;具体参照uniapp文档config beforeRequest(config)// 请求地址拼接config.url this.baseUrl config.url// 异…

WIN10安装gurobi给matlab使用(记录)

https://www.gurobi.com/downloads/gurobi-software/ 这是以前的matlab路径&#xff0c;需要修改成新的 使用校园网激活一下 运行gurobi_setup Google报错信息&#xff0c;发现mathwork官方的解释是&#xff1a;找不到相关的dll文件&#xff0c;所以mex无效。 解决方案&…

Unity | Shader基础知识(第八集:案例<漫反射材质球>)

目录 一、本节介绍 1 上集回顾 2 本节介绍 二、什么是漫反射材质球 三、 漫反射进化史 1 三种算法结果的区别 2 具体算法 2.1 兰伯特逐顶点算法 a.本小节使用的unity自带结构体。 b.兰伯特逐顶点算法公式 c.代码实现——兰伯特逐顶点算法 2.2 代码实现——兰伯特逐…

Windows下结束进程

可以用命令 netstat -ano | findstr :8088 直接找到端口号为8088的进程PID&#xff1b; 根据PID进程号结束进程 &#xff1a;taskkill /pid 14696 -t -f ;

研发提效必备技能:手把手教你基于Docker搭建Maven私服仓库

沉淀&#xff0c;成长&#xff0c;突破&#xff0c;帮助他人&#xff0c;成就自我。 大家好&#xff0c;我是冰河~~ 在研发的过程中&#xff0c;很多企业都会针对自身业务特点来定制研发一些工具类库&#xff0c;但是这些工具类库又不会对外公开&#xff0c;那如何在组织内部共…

如何使用支付宝的沙箱环境在本地配置模拟支付并发布至公网测试

文章目录 前言1. 下载当面付demo2. 修改配置文件3. 打包成web服务4. 局域网测试5. 内网穿透6. 测试公网访问7. 配置二级子域名8. 测试使用固定二级子域名访问 前言 在沙箱环境调试支付SDK的时候&#xff0c;往往沙箱环境部署在本地&#xff0c;局限性大&#xff0c;在沙箱环境…