一般我们会把常用的属性放在工程的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. winform textbox 不能唤醒windows 平板的软键盘解决办法

    这个问题,研究了将近两个小时,baidu,google,好大一会,windows 平板本身的应用程序,必须浏览器,notepad都是可以自动唤起软键盘的,但是我的winfrom 程序就是不可以,起先怀 ...

  2. touchWX 自定义组件以及传值

    创建如图文件 index.wxc: <template> <view class="wx-test" bindtap="handleTap"& ...

  3. Java中的数据结构有哪些?HashMap的工作原理是什么?

    Java中常用数据结构 常用的数据结构有哈希表,线性表,链表,java.util包中有三个重要的接口:List,Set,Map常用来实现基本的数据结构 HashMap的工作原理 HashMap基于ha ...

  4. android webview 输入法键盘遮挡输入框的问题

    新建一个工具类: /** * 解决webView键盘遮挡问题的类 * Created by zqy on 2016/11/14. */ public class KeyBoardListener { ...

  5. 2018-8-10-win10-uwp-气泡

    title author date CreateTime categories win10 uwp 气泡 lindexi 2018-08-10 19:16:50 +0800 2018-2-13 17: ...

  6. ulimit - 获取和改变用户的限制设定

    大纲 #include <ulimit.h> long ulimit(int cmd, long newlimit); 描述 警告: 这个函数已经被废弃. glibc 不再提供这个包含文件 ...

  7. centos7 sshd 安全设置

    ssh 的安全机制 1.SSH之所以能够保证安全,原因在于它采用了非对称加密技术(RSA)加密了所有传输的数据.   2.传统的网络服务程序,如FTP等在网络上用明文传送数据.用户帐号和用户口令,很容 ...

  8. 【学术篇】2.28测试T2 线段 拓扑排序

    题目: 思路: 看到这种找前后的题目... 第一反应就是拓扑排序_(:з」∠)_ 每条线段都有左右两个端点咯, 然后就乱搞吧.. 我们用\(i\)和\(i'\)分别表示第\(i\)条线段的左右端点.. ...

  9. 全球首个开放应用模型 OAM 开源

    业界要闻 全球首个开放应用模型 OAM 开源 2019 年 10 月 17 日,阿里巴巴合伙人.阿里云智能基础产品事业部总经理蒋江伟(花名:小邪)在 Qcon 上海重磅宣布,阿里云与微软联合推出开放应 ...

  10. Python对象继承set类型

    Python对象继承set类型 class Feature(set): def __init__(self): set.__init__(self) # 这里演示将Feature类的加号重载成set. ...