【新姿势】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);
        }
    }
}


    @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字段名相同,但类型为基本数据类型,使用此注解不能设置单位

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android WorkManager入门(一)

WorkManager入门 前言一、WorkManager是什么&#xff1f;二、使用1.添加依赖2.定义工作3.创建 WorkRequest并提交 一次性的任务&#xff08;OneTimeWorkRequest&#xff09;4.setExpedited 加急方法5. setInitialDelay 延时任务6.约束 总结参考资料 前言 在当今快节奏的生活中…

Volta简单介绍

Volta是一款强大的JavaScript工具管理器&#xff0c;它简化了命令行工具的安装和管理。通过Volta&#xff0c;开发者可以轻松地在多个项目中切换和配置Node.js、npm以及其它JavaScript工具版本&#xff0c;提高开发效率和环境一致性。 什么是 Volta Volta 是一种管理 JavaScri…

如何在公网环境使用固定域名远程访问内网BUG管理系统协同办公

文章目录 前言1. 本地安装配置BUG管理系统2. 内网穿透2.1 安装cpolar内网穿透2.2 创建隧道映射本地服务3. 测试公网远程访问4. 配置固定二级子域名4.1 保留一个二级子域名5.1 配置二级子域名6. 使用固定二级子域名远程 前言 BUG管理软件,作为软件测试工程师的必备工具之一。在…

056:vue工具 --- CSS在线格式化

第056个 查看专栏目录: VUE ------ element UI 专栏目标 在vue和element UI联合技术栈的操控下&#xff0c;本专栏提供行之有效的源代码示例和信息点介绍&#xff0c;做到灵活运用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安装、引用&#xff0c;模板使…

台湾虾皮本土店铺:如何在台湾虾皮本土店铺开展电商业务

在台湾地区&#xff0c;虾皮&#xff08;Shopee&#xff09;是一款备受欢迎的电商平台。虾皮拥有强大的技术团队、丰富的电商经验和对市场的深刻理解。虾皮本土店铺凭借其在出售、物流、回款、售后、仓储等方面的一条龙服务&#xff0c;为广大卖家提供了全方位的保障和支持。如…

【HCIP学习记录】OSPF之DD报文

1.OSPF报文格式 24字节 字段长度含义Version1字节版本&#xff0c;OSPF的版本号。对于OSPFv2来说&#xff0c;其值为2。Type1字节类型&#xff0c;OSPF报文的类型&#xff0c;有下面几种类型&#xff1a; 1&#xff1a;Hello报文&#xff1b;● 2&#xff1a;DD报文&#xff1…

人工智能解决方案工程师,究竟是个怎样的职业?

人工智能解决方案工程师是专注于利用人工智能技术为企业和组织提供解决方案的专业人员。 他们在人工智能技术的基础上&#xff0c;结合业务需求和场景&#xff0c;设计和开发定制化的智能系统&#xff0c;以解决特定的问题或优化业务流程。 人工智能解决方案工程师需要具备一系…

ros2 学习04 工作空间说明及示例

ros2 术语说明&#xff1a; 大家在学习其他的开发语言之前的学习和开发中&#xff0c;应该有接触过某些集成开发环境&#xff0c;比如Visual Studio、Eclipse、Qt Creator等&#xff0c;当我们想要编写程序之前&#xff0c;都会在这些开发环境的工具栏中&#xff0c;点击一个“…

win环境下启动kafka Port already in use: 6688; nested exception is

背景 zk启动成功后&#xff0c;接下来启动kafka&#xff0c;再启动kafka后一直说端口被占用。 端口占用解决办法: netstat -aon|findstr 9092 taskkill -f -pid 7780 杀掉后&#xff0c;再次启动kafka时&#xff0c;问题并未解决 后来修改了批处理文件kafka-run-class.bat中…

从零开始学习Web自动化:用Python和Selenium实现网站登录功能!

Web自动化测试实战项目&#xff1a;使用Selenium和Python完成网站登录功能的自动化测试 本文将介绍如何使用Selenium和Python编写自动化测试脚本&#xff0c;对网站登录功能进行测试。我们将通过模拟用户在网站上输入用户名和密码&#xff0c;并点击登录按钮&#xff0c;来检验…

测试工具Jmeter:设置中文界面

首先我们打开Jmeter所在的文件&#xff0c;进入bin目录&#xff0c;打开Jmeter.properties&#xff1a; 打开后找到languageen&#xff1a; 改为zh_CN: 保存关闭&#xff0c;然后再打开Jmeter&#xff1a; 英文并不会显得高级&#xff0c;能做到高效的性能测试才是高级的。

明理信息科技打造专属个人或企业知识付费平台,核心功能设计

在当今信息爆炸的时代&#xff0c;知识管理已经成为了每个人必须面对的问题。然而&#xff0c;市面上的知识付费平台大多数都是通用的&#xff0c;无法满足个性化需求。 因此&#xff0c;明理信息科技提供了一款专属定制的适合个人的知识付费平台。核心产品能力如下&#xff1…

宠物新手必读:5款公认性价比高的猫罐头测评

很多人在买猫罐头的时候&#xff0c;可是费了老鼻子劲儿了。他们浏览了各大平台&#xff0c;读了大量的评测文章&#xff0c;就想着找到最好的那一个。但最后他们发现&#xff0c;很多所谓的「实测」都是虚的&#xff0c;假的。花了几天时间&#xff0c;结果选了个垃圾猫罐头&a…

Elasticsearch——深入原理

在正式介绍Elasticsearch的具体功能以前&#xff0c;将介绍Elasticsearch中比较重要的原理与机制。这有助于理解Elasticsearch的内部机制&#xff0c;以及从表面功能深入了解其背后的逻辑本质。主要内容如下&#xff1a; 搜索引擎的基本原理和组成结构。Elasticsearch集群的形…

Java基础语法之内部类

什么是内部类 就是在一个类中又定义了另一个类 分类 实例内部类 即未被static修饰的内部类 1.外部类中的任何成员都可以在内部类里面直接访问&#xff0c;不管这个成员是什么权限 2.内部类对象的创建必须是在有外部类成员的前提下 这是错误的&#xff0c;那如何实例化呢&a…

个人熟悉C语言,准备学习嵌入式,用得上吗?

今日话题&#xff0c;准备学习嵌入式&#xff0c;熟悉C语言用得上吗&#xff1f;C语言具有高效的性能和接近硬件的特性&#xff0c;因此在嵌入式开发中有着广泛的应用&#xff0c;包括系统级编程和驱动程序开发等方面。实际上&#xff0c;C语言在嵌入式开发中扮演着非常关键的角…

八股文打卡day3——计算机网络(3)

面试题&#xff1a;请讲一下四次挥手的过程&#xff1f; 1.客户端发送FIN数据包给服务器&#xff0c;表示客户端不再发送数据给服务器&#xff0c;想要断开这个方向的连接。 2.服务器收到客户端的FIN包之后&#xff0c;发送ACK包给客户端&#xff0c;对收到的FIN包进行收到确认…

大数据机器学习-梯度下降:从技术到实战的全面指南

大数据机器学习-梯度下降&#xff1a;从技术到实战的全面指南 文章目录 大数据机器学习-梯度下降&#xff1a;从技术到实战的全面指南一、简介什么是梯度下降&#xff1f;为什么梯度下降重要&#xff1f; 二、梯度下降的数学原理代价函数&#xff08;Cost Function&#xff09;…

VueStu01-Vue是什么

1.概念 Vue 是一个 用于构建用户界面 的 渐进式 框架 。 2.构建用户界面 基于数据渲染出用户看到的页面。 3.渐进式 Vue的学习是循序渐进的&#xff0c;可以学一点用一点&#xff0c;不必全部学完才能用。哪怕你只学了 声明式渲染 这一个小部分的内容&#xff0c;你也可以完成…

商业加速终极指南:创业家的10个关键步骤

多年来&#xff0c;前沿的初创企业一直在塑造整个行业&#xff0c;引入新技术、更精简的业务模式以及深受客户喜爱的开箱即用的产品。这不仅仅是一种短暂的趋势&#xff0c;而是我们的商业格局发生了根本性的转变&#xff0c;在这种情况下&#xff0c;率先抓住新的增长机遇可以…