一般我们会把常用的属性放在工程的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支持的更多相关文章

  1. 如何优雅地在 Spring Boot 中使用自定义注解,AOP 切面统一打印出入参日志 | 修订版

    欢迎关注个人微信公众号: 小哈学Java, 文末分享阿里 P8 资深架构师吐血总结的 <Java 核心知识整理&面试.pdf>资源链接!! 个人网站: https://www.ex ...

  2. Spring Boot中使用MyBatis注解配置详解(1)

    之前在Spring Boot中整合MyBatis时,采用了注解的配置方式,相信很多人还是比较喜欢这种优雅的方式的,也收到不少读者朋友的反馈和问题,主要集中于针对各种场景下注解如何使用,下面就对几种常见 ...

  3. 在Spring Boot中使用 @ConfigurationProperties 注解

    但 Spring Boot 提供了另一种方式 ,能够根据类型校验和管理application中的bean. 这里会介绍如何使用@ConfigurationProperties.继续使用mail做例子. ...

  4. 在Spring Boot中使用 @ConfigurationProperties 注解, @EnableConfigurationProperties

    但 Spring Boot 提供了另一种方式 ,能够根据类型校验和管理application中的bean. 这里会介绍如何使用@ConfigurationProperties.继续使用mail做例子. ...

  5. Spring Boot 中使用 @Transactional 注解配置事务管理

    事务管理是应用系统开发中必不可少的一部分.Spring 为事务管理提供了丰富的功能支持.Spring 事务管理分为编程式和声明式的两种方式.编程式事务指的是通过编码方式实现事务:声明式事务基于 AOP ...

  6. Spring Boot中使用@Transactional注解配置事务管理

    事务管理是应用系统开发中必不可少的一部分.Spring 为事务管理提供了丰富的功能支持.Spring 事务管理分为编程式和声明式的两种方式.编程式事务指的是通过编码方式实现事务:声明式事务基于 AOP ...

  7. Spring boot中相关的注解

    一.相关类中使用的注解 @RestController:REST风格的控制器 @RequestMapping:配置URL和方法之间的映射 @SpringBootApplication:应用程序入口类 ...

  8. spring boot中的jave注解学习

    在spring中,不仅框架作者会使用java注解,开发者也常使用. 可以随手给个例子:在org.springframework.boot.autoconfigure.jdbc.DataSourcePr ...

  9. Spring Boot 中使用自定义注解,AOP 切面打印出入参日志及Dubbo链路追踪透传traceId

    一.使用背景 开发排查系统问题用得最多的手段就是查看系统日志,在分布式环境中一般使用 ELK 来统一收集日志,但是在并发大时使用日志定位问题还是比较麻烦,由于大量的其他用户/其他线程的日志也一起输出穿 ...

随机推荐

  1. python代码技巧总结(更新至17条)

    怎么提高代码水平?答:看牛逼的代码! 牛逼的代码怎么写的?简单,明确,优雅! 怎么简单,明确,优雅?学技巧! 下面搜罗了一些有才格子褂青年的总结,哈哈 1.检查 Python 中的对象 调用 dir( ...

  2. 008-Java的StringBuilder和StringBuffer

    StringBuffer 和 StringBuilder 与String的不同 String Java中十分重要的类;被声明为final class.除了hash这个属性, 其他属性也均声明为fina ...

  3. 微信小程序中实现左右滑动图片翻页

    页面代码 <swiper class="container" indicator-dots="{{indicatordots}}" autoplay=&q ...

  4. 批量Ping执行Bash脚本

    #!/bin/bash # Ping Batch Script # 连接超时时间 TMOUT= # 最大线程数 MAX_THREAD= # 保留内存大小 MIN_MEM= # 默认ip配置,可通过 - ...

  5. document.write()创建元素有缺陷,

    如果在页面加载完毕后,此时通过这种方式创建元素,那么页面上存在的所有内容全部被干掉.

  6. sqoop导出数据|Hive|HDFS和脚本编写

    导出数据 在Sqoop中,“导出”概念指:从大数据集群(HDFS,HIVE,HBASE)向非大数据集群(RDBMS)中传输数据,叫做:导出,即使用export关键字. HIVE/HDFS到RDBMS ...

  7. NX二次开发-UFUN工程图表格注释检索默认单元格首选项UF_TABNOT_ask_default_cell_prefs

    NX9+VS2012 #include <uf.h> #include <uf_tabnot.h> #include <NXOpen/Part.hxx> #incl ...

  8. Qt5编译使用QFtp

    使用 QNetworkAccessManager 可以实现 Ftp 的上传/下载功能(参考:Qt之FTP上传/下载),但有些原本 QFtp 有的功能 QNetworkAccessManager 却没有 ...

  9. 1.RabbitMQ介绍

    MQ全称为Message Queue, 消息队列(MQ)是一种应用程序对应用程序的通信方法.应用程序通过读写出入队列的消息(针对应用程序的数据)来通信,而无需专用连接来链接它们.消息传递指的是程序之间 ...

  10. solr添加IK分词和自己定义词库

    下载IK分词IK Analyzer 2012FF_hf1.zip 下载地址:http://yunpan.cn/cdvATy8899Lrw (提取码:c10d) 1.将IKAnalyzer2012FF_ ...