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

相关文章

SpringMVC高效获取JavaBean对象指南

《SpringMVC高效获取JavaBean对象指南》SpringMVC通过数据绑定自动将请求参数映射到JavaBean,支持表单、URL及JSON数据,需用@ModelAttribute、@Requ... 目录Spring MVC 获取 JavaBean 对象指南核心机制:数据绑定实现步骤1. 定义 Ja

nginx启动命令和默认配置文件的使用

《nginx启动命令和默认配置文件的使用》:本文主要介绍nginx启动命令和默认配置文件的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录常见命令nginx.conf配置文件location匹配规则图片服务器总结常见命令# 默认配置文件启动./nginx

SQL Server修改数据库名及物理数据文件名操作步骤

《SQLServer修改数据库名及物理数据文件名操作步骤》在SQLServer中重命名数据库是一个常见的操作,但需要确保用户具有足够的权限来执行此操作,:本文主要介绍SQLServer修改数据... 目录一、背景介绍二、操作步骤2.1 设置为单用户模式(断开连接)2.2 修改数据库名称2.3 查找逻辑文件名

C++中RAII资源获取即初始化

《C++中RAII资源获取即初始化》RAII通过构造/析构自动管理资源生命周期,确保安全释放,本文就来介绍一下C++中的RAII技术及其应用,具有一定的参考价值,感兴趣的可以了解一下... 目录一、核心原理与机制二、标准库中的RAII实现三、自定义RAII类设计原则四、常见应用场景1. 内存管理2. 文件操

canal实现mysql数据同步的详细过程

《canal实现mysql数据同步的详细过程》:本文主要介绍canal实现mysql数据同步的详细过程,本文通过实例图文相结合给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的... 目录1、canal下载2、mysql同步用户创建和授权3、canal admin安装和启动4、canal

SpringBoot服务获取Pod当前IP的两种方案

《SpringBoot服务获取Pod当前IP的两种方案》在Kubernetes集群中,SpringBoot服务获取Pod当前IP的方案主要有两种,通过环境变量注入或通过Java代码动态获取网络接口IP... 目录方案一:通过 Kubernetes Downward API 注入环境变量原理步骤方案二:通过

使用SpringBoot整合Sharding Sphere实现数据脱敏的示例

《使用SpringBoot整合ShardingSphere实现数据脱敏的示例》ApacheShardingSphere数据脱敏模块,通过SQL拦截与改写实现敏感信息加密存储,解决手动处理繁琐及系统改... 目录痛点一:痛点二:脱敏配置Quick Start——Spring 显示配置:1.引入依赖2.创建脱敏

使用Python实现获取屏幕像素颜色值

《使用Python实现获取屏幕像素颜色值》这篇文章主要为大家详细介绍了如何使用Python实现获取屏幕像素颜色值,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 一、一个小工具,按住F10键,颜色值会跟着显示。完整代码import tkinter as tkimport pyau

详解如何使用Python构建从数据到文档的自动化工作流

《详解如何使用Python构建从数据到文档的自动化工作流》这篇文章将通过真实工作场景拆解,为大家展示如何用Python构建自动化工作流,让工具代替人力完成这些数字苦力活,感兴趣的小伙伴可以跟随小编一起... 目录一、Excel处理:从数据搬运工到智能分析师二、PDF处理:文档工厂的智能生产线三、邮件自动化:

python获取cmd环境变量值的实现代码

《python获取cmd环境变量值的实现代码》:本文主要介绍在Python中获取命令行(cmd)环境变量的值,可以使用标准库中的os模块,需要的朋友可以参考下... 前言全局说明在执行py过程中,总要使用到系统环境变量一、说明1.1 环境:Windows 11 家庭版 24H2 26100.4061