bean中字段获取配置文件中的数据

2024-03-01 19:08

本文主要是介绍bean中字段获取配置文件中的数据,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

如果想要将配置文件中的配置信息赋于bean中字段可以使用@Value和@ConfigurationProperties这两种形式。在@Value中一般使用的是@Value(“${xxx.yyy.zzz:defaultValue}”)这种形式,我们可以获取配置文件中key对应的值,如果找不到该配置则使用后面跟的那个默认值。

例如配置文件application.properties中有
spring.application.name=myProject
feign.hystrix.enabled=true可以使用该种形式获取对应的配置key对应的value值 
@Value("${spring.application.name}”)
String applicationName; 

@Value的实现方式主要与org.springframework.core.env.PropertySource 、org.springframework.core.env.Environment 有关。PropertySource可以理解为数据源,它其中有个方法叫做getProperty(String name),通过key的名字获取数据源中对应的key-value对的value值,我们的配置文件就是一个数据源。
Environment 即项目的环境配置信息它其中有两个方法,String resolvePlaceholders(String text) 解析@Value("${xxxx}")xxxx,

ConfigurableEnvironment 中包含MutablePropertySources getPropertySources()获取所有的PropertySource实例,PS:MutablePropertySource实现了PropertySource接口。那么从上我们就可以大概推出@Value的执行过程
(1)environment使用resolvePlaceholders解析@Value中的配置key
(2)environment使用getPropertysources方法获取MutablePropertySources,它其中有一个包含所有的PropertySource的list
(3)利用MutablePropertySources对所有的PropertySource进行遍历,使用getProperty查询对应的value

那么除了将配置信息放在配置文件中,从上面我们看出来其实是从propertySource中获取key对应的value,所有我们还可以将配置信息放在数据库或其他存储媒介中,只是在项目初始化时,需要将对应的配置信息生成一个propertySource对象,放入MutablePropertySources中,简单给个代码。

/*** 邮件配置信息*/
@Data
@Component
public class MailConfig {@Value("${mail.host}")private String host;@Value("${mail.username}")private String username;@Value("${mail.password}")private String password;
}@Test
public void test2() {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();//模拟从db中获取配置信息Map<String, Object> mailInfoFromDb = DbUtil.getMailInfoFromDb();//将其丢在MapPropertySource中(MapPropertySource类是spring提供的一个类,是PropertySource的子类)MapPropertySource mailPropertySource = new MapPropertySource("mail", mailInfoFromDb);//将mailPropertySource丢在Environment中的PropertySource列表的第一个中,让优先级最高context.getEnvironment().getPropertySources().addFirst(mailPropertySource);/*上面这段是关键 end*/context.register(MainConfig2.class);context.refresh();MailConfig mailConfig = context.getBean(MailConfig.class);System.out.println(mailConfig);
}

一般情况下我们是使用@Value(“${xxx.yyy}”)去获取对应配置文件中的value,其实还有一种形式是@Value(“#{}”),那么这个#标记的@Value是干嘛的呢?#表示执行一个spel表达式
(1) 获取常量 @Value(“#{1}”)、 @Value(“#{‘字符串常量’}”)
(2) 获取bean的属性,但是要确保被获取属性的bean和本bean在同一个容器中,如@Value(“#{aBean.name}”),获取aBean的name属性
(3) 调用bean的方法,如@Value(“#{aBean.getName}”),获取aBean的getName方法返回值下面再简单说一下@ConfigurationProperties,它可以利用配置前缀获取配置中的配置信息,一般用于配置类之上,举个简单的小例子。以七牛公共和私有bucket配置为例

bootstrap.yml中有
qiniu:buckets:private:bucket: yqg-private-secretdomain: http://private-domain/public:bucket: yqg-public-testdomain: https://public-domain/那么其对应的配置类格式为,可以看到我们甚至可以根据配置文件中配置属性的层级去定义配置类的结构
@Data
@ConfigurationProperties(prefix = "qiniu")
public class QiniuProperties {private Map<String, BucketConfig> buckets = new HashMap<>();@Datapublic static class BucketConfig {private String bucket;private String domain;}
}

由此我们可以看出一些@Value和@ConfigurationProperties的区别,如果仅仅想获取其中一个配置的value那么就用@value,如果想要获取一类配置的value,那么可以使用@ConfigurationProperties,它一个用在属性字段上,一个用在类上,且@Value支持$和#两种形式,#可以获取常量、其他bean的属性字段,方法返回值。

@Value和@ConfigurationProperties动态刷新

现在大家的项目中一般都会使用配置中心用来动态获取配置信息,不管是Spring-boot的配置管理、zookeeper还是携程的apollo都为我们提供了便捷的配置管理功能。当配置中心的配置发生改变时,会通知客户端服务,更改environment中的对应的配置信息,当environment发生更改时会触发EnvironmentChangeEvent事件,其中包括了keys字段,就是发生变更的配置名。
@ConfigurationProperties原本就支持配置自动刷新,在ConfigurationPropertiesRebinder中会监听EnvironmentChangeEvent事件,将所有被@ConfigurationProperties注解修饰的bean进行重新绑定,此时就会刷新@ConfigurationProperties标识bean中的属性值。而@Value注解标识的字段并不会自动刷新,需要搭配@RefreshScope进行刷新。

如果我们使用了@Value,创建bean时获取的配置value值会赋值给在bean中对应属性字段,它只会在bean创建的过程中获取一次,即使以后通过配置中心改变了environment中key对应的value,@Value修饰字段的值也不会改变。那么该如何对它们进行动态刷新呢?
       在spring-cloud中提供了一个注解叫做@RefreshScope,它可以提供配置的动态刷新。先进到@RefreshScope这个注解中去看一下,注解的内容很简单就是把使用了该注解的类,它的@Scope作用域置为fresh,ScopeProxyMode使用TARGET_CLASS,看一下它的英文注释,大概就是说使用该注解修饰的bean可以在运行时刷新,每次使用bean时都会创建一个新的bean,而ScopedProxyMode.TARGET_CLASS表示创建该bean时实际返回的通过cglib产生的一个代理对象。

/*** Convenience annotation to put a <code>@Bean</code> definition in* {@link org.springframework.cloud.context.scope.refresh.RefreshScope refresh scope}.* Beans annotated this way can be refreshed at runtime and any components that are using* them will get a new instance on the next method call, fully initialized and injected* with all dependencies.* * @author Dave Syer**/
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Scope("refresh")
@Documented
public @interface RefreshScope {/*** @see Scope#proxyMode()*/ScopedProxyMode proxyMode() default ScopedProxyMode.TARGET_CLASS;
}

它的实现类RefreshScope.java->GenericScope->Scope(接口),可以看一下它的类注释,我就不贴了,其中写了被@RefreshScope修饰的bean会被置为懒加载,只有在第一次使用它的时候才会进行创建,如果有其他的bean依赖与它,那么它获取的只是被@RefreshScope修饰bean的一个代理。
(1)当第一次使用时,会将对应bean创建并生成代理,然后放入到一个cache之中,当不刷新时,获取的代理对象都是这一个
(2)当属性发生改变,environment中对应的value发送改变,然后会发出refresh请求,会调用RefreshScope.refreshAll()或refresh(string name)方法,前者为刷新全部配置,后者为刷新指定bean的配置,执行GenericScope的destory()或destory(name)方法,并发送refreshScope事件,供监听处理。
(3)在GenericScope的destory方法中会将cache中全部或指定name的代理对象缓存删除,然后对应代理对象销毁
(4)当下次在使用对象中的属性或方法时会调用GenericScope的get方法重新利用新的配置value值生成代理对象,并放入缓存

下面简单给个代码

//bootstrap.yml
mail:username: myUserName//配置类
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;@Component
@RefreshScope
public class TestRefreshScope {@Value("${mail.username}")private String name;public String getName() {return name;}
}//直接在idea里建了个eureka项目,在它启动类里写的测试代码
@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {public static void main(String[] args) {ConfigurableApplicationContext context = SpringApplication.run(EurekaServerApplication.class, args);System.out.println("在修改配置值之前");for (int i=1; i<=3; i++) {TestRefreshScope obejct = context.getBean(TestRefreshScope.class);System.out.println(obejct);System.out.println(obejct.getName());System.out.println("================================");}System.out.println("刷新后");//模拟自定义propertySource并刷新现有的邮箱配置,它可以来自数据库等其他存储中介for (int i=1; i<=3; i++) {refreshMailPropertySource(context);RefreshScope refreshScope = context.getBean(RefreshScope.class);//手动触发refresh,正常应该是执行一个refresh post请求refreshScope.refresh("testRefreshScope");TestRefreshScope obejct = context.getBean(TestRefreshScope.class);System.out.println(obejct);System.out.println(obejct.getName());System.out.println("================================");}}private static void refreshMailPropertySource(ConfigurableApplicationContext context) {Map<String, Object> mailInfo = new HashMap<>();String uuid = UUID.randomUUID().toString();System.out.println("新生成的uuid="+uuid);mailInfo.put("mail.username", uuid);//将其丢在MapPropertySource中(MapPropertySource类是spring提供的一个类,是PropertySource的子类)MapPropertySource mailPropertySource = new MapPropertySource("mail", mailInfo);context.getEnvironment().getPropertySources().addFirst(mailPropertySource);}
}

执行结果如下

在修改配置值之前
com.springboot.eurekaserver.TestRefreshScope@6546371
myUserName
================================
com.springboot.eurekaserver.TestRefreshScope@6546371
myUserName
================================
com.springboot.eurekaserver.TestRefreshScope@6546371
myUserName
================================
刷新后
新生成的uuid=f48dd171-440b-48cd-b5be-0e3ebd6d2668
com.springboot.eurekaserver.TestRefreshScope@227a933d
f48dd171-440b-48cd-b5be-0e3ebd6d2668
================================
新生成的uuid=c13c562c-5d5f-4607-ac5b-46356fb448a1
com.springboot.eurekaserver.TestRefreshScope@7bc2ae16
c13c562c-5d5f-4607-ac5b-46356fb448a1
================================
新生成的uuid=d49de0bf-11eb-4589-8eb7-f6d5ec0022ba
com.springboot.eurekaserver.TestRefreshScope@64910b2d
d49de0bf-11eb-4589-8eb7-f6d5ec0022ba
================================

这篇关于bean中字段获取配置文件中的数据的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/763508

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

【Prometheus】PromQL向量匹配实现不同标签的向量数据进行运算

✨✨ 欢迎大家来到景天科技苑✨✨ 🎈🎈 养成好习惯,先赞后看哦~🎈🎈 🏆 作者简介:景天科技苑 🏆《头衔》:大厂架构师,华为云开发者社区专家博主,阿里云开发者社区专家博主,CSDN全栈领域优质创作者,掘金优秀博主,51CTO博客专家等。 🏆《博客》:Python全栈,前后端开发,小程序开发,人工智能,js逆向,App逆向,网络系统安全,数据分析,Django,fastapi

烟火目标检测数据集 7800张 烟火检测 带标注 voc yolo

一个包含7800张带标注图像的数据集,专门用于烟火目标检测,是一个非常有价值的资源,尤其对于那些致力于公共安全、事件管理和烟花表演监控等领域的人士而言。下面是对此数据集的一个详细介绍: 数据集名称:烟火目标检测数据集 数据集规模: 图片数量:7800张类别:主要包含烟火类目标,可能还包括其他相关类别,如烟火发射装置、背景等。格式:图像文件通常为JPEG或PNG格式;标注文件可能为X

pandas数据过滤

Pandas 数据过滤方法 Pandas 提供了多种方法来过滤数据,可以根据不同的条件进行筛选。以下是一些常见的 Pandas 数据过滤方法,结合实例进行讲解,希望能帮你快速理解。 1. 基于条件筛选行 可以使用布尔索引来根据条件过滤行。 import pandas as pd# 创建示例数据data = {'Name': ['Alice', 'Bob', 'Charlie', 'Dav

SWAP作物生长模型安装教程、数据制备、敏感性分析、气候变化影响、R模型敏感性分析与贝叶斯优化、Fortran源代码分析、气候数据降尺度与变化影响分析

查看原文>>>全流程SWAP农业模型数据制备、敏感性分析及气候变化影响实践技术应用 SWAP模型是由荷兰瓦赫宁根大学开发的先进农作物模型,它综合考虑了土壤-水分-大气以及植被间的相互作用;是一种描述作物生长过程的一种机理性作物生长模型。它不但运用Richard方程,使其能够精确的模拟土壤中水分的运动,而且耦合了WOFOST作物模型使作物的生长描述更为科学。 本文让更多的科研人员和农业工作者