在Spring-boot中,为@Value注解添加从数据库读取properties支持
一般我们会把常用的属性放在工程的classpath文件夹中,以property,yaml或json的格式进行文件存储,便于Spring-boot在初始化时获取。
@Value则是Spring一个非常有用的注解,可以在初始化时很方便的对Bean的入参变量进行赋值,例如:
@Bean
public BusinessClient businessClient (@Value("http://baseUrl/") String baseUrl) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit.create(BusinessClient .class);
于是,初始化好的Business Client进行http请求时,默认的baseurl都是”http://baseUrl“。
实际上,@Value还支持一种特殊的写法:”${some.proptery.key}”,即将property的key值写在花括号中。例如,我有一个property为aerexu.basurl=http://baseUrl2,将上例中的@Value改写成@Value("${aerexu.basurl}")
,baseUrl实际获取到的值是http://baseUrl2。
这个特性是利用Spring的bean PropertySourcesPlaceholder实现的,Spring boot已经在初始化时帮我们自动实例化了该bean。若是传统的Spring工程,则需要主动实例化,如下:
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setPlaceholderPrefix(PlaceholderConfigurerSupport.DEFAULT_PLACEHOLDER_PREFIX);
configurer.setPlaceholderSuffix(PlaceholderConfigurerSupport.DEFAULT_PLACEHOLDER_SUFFIX);
configurer.setValueSeparator(PlaceholderConfigurerSupport.DEFAULT_VALUE_SEPARATOR);
return configurer;
}
一般情况下,property存在工程中的文件就可以了,但带来的坏处是如果属性需要改变,必须重新发布工程。比如,对接上例中的url,可能会变为https,可能端口会变化。所以,这种类型的属性放在数据库中更合适。
然而将属性存储在数据库中后,@Value对应的值就无法正常解析了。因此,这里提供一种hack的方法,使得@Value可以正常解析。
PropertySourcesPlaceholder在解析属性时,都是从ConfigurableEnvironment中进行寻找的。当ConfigurableEnvironment没有存在的属性时,${}写法的@Value就无法解析了。因此,需要通过特殊的处理,将存储在数据库中的属性注入到ConfigurableEnvironment中。本文定义了一个LoadFromDatabasePropertyConfig类实现该功能,其代码如下:
@Configuration
@Slf4j
public class LoadFromDatabasePropertyConfig {
@Autowired
private ConfigurableEnvironment env;
@Autowired
private SysPropertyResourceMapper propertyResourceMapper;
@PostConstruct
public void initializeDatabasePropertySourceUsage() {
MutablePropertySources propertySources = env.getPropertySources();
try {
Map<String, Object> propertyMap = propertyResourceMapper.selectAll().stream()
.collect(Collectors.toMap(SysPropertyResource::getPropertyName, SysPropertyResource::getPropertyValue));
Properties properties = new Properties();
properties.putAll(propertyMap);
PropertiesPropertySource dbPropertySource = new PropertiesPropertySource("dbPropertySource", properties);
Pattern p = Pattern.compile("^applicationConfig.*");
String name = null;
boolean flag = false;
for (PropertySource<?> source : propertySources) {
if (p.matcher(source.getName()).matches()) {
name = source.getName();
flag = true;
log.info("Find propertySources ".concat(name));
break;
}
}
log.info("=========================================================================");
if(flag) {
propertySources.addBefore(name, dbPropertySource);
} else {
propertySources.addFirst(dbPropertySource);
}
} catch (Exception e) {
log.error("Error during database properties setup", e);
throw new RuntimeException(e);
}
}
}
上述代码的具体思路是将数据库中的所有需要的属性读出,通过Properties类转换为Spring可用的PropertiesPropertySource,并取名为dbPropertySource。随后利用正则匹配,从已有的所有属性中找到名称以applicationConfig开头的属性(该属性即是所有配置在文件中的property所解析成的对象),并将dbPropertySource存储在其之前。这样当文件和数据库中同时存在key相等的属性时,会优先使用数据库中存储的value。
需要注意的是,上述方案提供的属性解析,必须在数据库相关的bean都实例化完成后才可进行。且为了保证bean在实例化时,数据库属性已经被加入到ConfigurableEnvironment中去了,必须添加@DependsOn注解。上面的BusinessClient的实例化就需更新成:
@Bean
@DependsOn("loadFromDatabasePropertyConfig")
public BusinessClient businessClient (@Value("${aerexu.basurl}") String baseUrl) {
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseUrl)
.addConverterFactory(GsonConverterFactory.create())
.build();
return retrofit.create(BusinessClient .class);
在Spring-boot中,为@Value注解添加从数据库读取properties支持的更多相关文章
- 如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志 | 修订版
欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 资深架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...
- Spring Boot中使用MyBatis注解配置详解(1)
之前在Spring Boot中整合MyBatis时,采用了注解的配置方式,相信很多人还是比较喜欢这种优雅的方式的,也收到不少读者朋友的反馈和问题,主要集中于针对各种场景下注解如何使用,下面就对几种常见 ...
- 在Spring Boot中使用 @ConfigurationProperties 注解
但 Spring Boot 提供了另一种方式 ,能够根据类型校验和管理application中的bean. 这里会介绍如何使用@ConfigurationProperties.继续使用mail做例子. ...
- 在Spring Boot中使用 @ConfigurationProperties 注解, @EnableConfigurationProperties
但 Spring Boot 提供了另一种方式 ,能够根据类型校验和管理application中的bean. 这里会介绍如何使用@ConfigurationProperties.继续使用mail做例子. ...
- Spring Boot 中使用 @Transactional 注解配置事务管理
事务管理是应用系统开发中必不可少的一部分.Spring 为事务管理提供了丰富的功能支持.Spring 事务管理分为编程式和声明式的两种方式.编程式事务指的是通过编码方式实现事务:声明式事务基于 AOP ...
- Spring Boot中使用@Transactional注解配置事务管理
事务管理是应用系统开发中必不可少的一部分.Spring 为事务管理提供了丰富的功能支持.Spring 事务管理分为编程式和声明式的两种方式.编程式事务指的是通过编码方式实现事务:声明式事务基于 AOP ...
- Spring boot中相关的注解
一.相关类中使用的注解 @RestController:REST风格的控制器 @RequestMapping:配置URL和方法之间的映射 @SpringBootApplication:应用程序入口类 ...
- spring boot中的jave注解学习
在spring中,不仅框架作者会使用java注解,开发者也常使用. 可以随手给个例子:在org.springframework.boot.autoconfigure.jdbc.DataSourcePr ...
- Spring Boot 中使用自定义注解,AOP 切面打印出入参日志及Dubbo链路追踪透传traceId
一.使用背景 开发排查系统问题用得最多的手段就是查看系统日志,在分布式环境中一般使用 ELK 来统一收集日志,但是在并发大时使用日志定位问题还是比较麻烦,由于大量的其他用户/其他线程的日志也一起输出穿 ...
随机推荐
- git 强制取消本地修改
本地的项目中修改不做保存操作,可以用到Git pull的强制覆盖,具体代码如下: git fetch --allgit reset --hard origin/master git fetch 指令是 ...
- HBase启动错误提示别的机器60000已经存在
已经用cm 安装好了cdh,需要在上面添加HBase,并且做一个HBase故障转移功能,现在需要配置2个HMaster 在不同的机器上. 启动出现异常信息: 2015-12-23 14:44:38, ...
- P3410 /// 最大流最小割
题目大意: https://www.luogu.org/problemnew/show/P3410 题解 https://www.cnblogs.com/2020pengxiyue/p/9463055 ...
- mongo数组修改器—$push、$ne、$addtoset、$pop、$pull
这几个方法也很有意思 $push 像已有的数组末尾加入一个元素,要是元素不存在,就会创建一个新的元素,如果元素存在了,就会再添加一个一模一样的元素,会造成元素的重复,所以在使用的时候,要确保该元素不存 ...
- pyJWT
现在用JWT 加密太火了,怎么能不跟上潮流?否则销售都不好意思出去吹牛逼! PyJWT是一个Python库,用来编码/解码JWT(JSON Web Token)的 1.定义:根据维基百科的定义,JSO ...
- set -x 调试shell
在上面的结果中,前面有“+”号的行是shell脚本实际执行的命令,前面有“++”号的行是执行trap机制中指定的命令,其它的行则是输出信息. shell的执行选项除了可以在启动shell时指定外,亦可 ...
- C# ASCII码和英文字母相互转换和ASCII码对照表
1.字母转换成ASCII码 string str = "hello"; ]; array = System.Text.Encoding.ASCII.GetBytes(str); / ...
- CSIC_716_20191204【网络编程 OSI 七层结构】
软件开发架构 C/S架构: Client: 客户端 Server: 服务端 比如: 微信客户端.QQ客户端等... 优点: - 软件的使用稳定 - 节省网络资源 缺点: - 安装麻烦,用户体验差 - ...
- mysql命令行执行时不输出列名(字段名),直接显示字段对应的数值
执行命令时加个-N参数就可以了 -N, –skip-column-names 比如说:mysql -uroot -p1234546 -N -e “select * from user;”
- 26.String类(1)
1. 下面是一个使用equals的例子: 我查看了一下源代码,string类中equals方法的源代码如下: public boolean equals(Object anObject) { if ( ...