在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 来统一收集日志,但是在并发大时使用日志定位问题还是比较麻烦,由于大量的其他用户/其他线程的日志也一起输出穿 ...
随机推荐
- 深入理解JAVA虚拟机原理之Dalvik虚拟机(三)
更多Android高级架构进阶视频学习请点击:https://space.bilibili.com/474380680 本文是Android虚拟机系列文章的第三篇,专门介绍Andorid系统上曾经使用 ...
- 【牛客提高训练营2B】分糖果
题目 发现自己一年之前非常垃圾 题目大意是给你一个\(n\)个点的环,给每个点一个\([1,a_i]\)的取值,并且满足环上任意相连两点权值不能相等,求方案数 考虑断环为链,发现不大会 不妨考虑所有\ ...
- 网络编程之 TCP-UDP的详细介绍
一.TCP协议 1. TCP协议的特点 1.TCP是面向连接的运输层协议.这就意味着,在使用该协议之前,必须建立TCP连接.在传输数据完毕后,必须释放已经建立的TCP连接. 2.每一条TCP连接只能有 ...
- 【SGU194】Reactor Cooling
题目大意 给定一个无源无汇的网络,边的容量有上下界限制,试构造一个合理的流量. 题目分析 求无源汇上下界的可行流模板题. ①增加一个附加源和汇\(S,T\). ②把每个节点的\(\sum b_{u,i ...
- P2290 [HNOI2004]树的计数
P2290 [HNOI2004]树的计数prufer序列模板题 #include <iostream> #include <cstdio> #include <queue ...
- PHPExcel导出数据量过大处理
今天使用PHPExce插件导不出数据,发现是数据量过大的原因,这里只做简单的处理. 1.导出超时处理:在执行页面添加:set_time_limit(0); 2.内存溢出:在执行页面添加:ini_set ...
- Thinkphp 3.2 去掉index.php
1.httpd.conf中去掉LoadModule rewrite_module modules/mod_rewrite.so 前面的#号 2.httpd.conf 中 AllowOverride ...
- sed 一 文本处理工具
简介 sed 采用的是流编辑模式: 最明显的特点是,在 sed 处理数据之前,需要预先提供一组规则,sed 会按照此规则来编辑数据. sed 会根据脚本命令来处理文本文件中的数据,这些命令要么从命令行 ...
- 【转】Git 修改已提交的commit注释
https://www.jianshu.com/p/098d85a58bf1 [重点] 通过git rebase -i HEAD~2 你想修改哪条注释 就把哪条注释前面的pick换成edit git ...
- 【历年真题】斐波那契数列logn做法
描述 [题解] 用矩阵乘法加速递推 [0 1] [1 1] [f[n-1]] [f[n-2]] = [f[n-1]] [f[n]] 求A矩阵的n-2次幂然后再乘B矩阵. 结果矩阵中的第二行第一列就是f ...