【SpringBoot 根底系列】自定义配置源的应用姿态介绍
后面一篇博文介绍了一个 @Value
的一些知识点,其中提了一个点,@Value
对应的配置,除了是配置文件中之外,能够从其余的数据源中获取么,如从 redis,db,http 中获取配置?
理解过 SpringCloud Config 的能够给出确切的答案,能够,而且用起来还老爽了,近程配置,反对配置动静刷新,接下来咱们来看一下,在 SpringBoot 中,如何配置自定义的数据源
<!– more –>
I. 我的项目环境
1. 我的项目依赖
本我的项目借助 SpringBoot 2.2.1.RELEASE
+ maven 3.5.3
+ IDEA
进行开发
开一个 web 服务用于测试
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
II. 自定义配置源
@Value
润饰的成员,绑定配置时,是从 Envrionment
中读取配置的,所以咱们须要做的就是注册一个自定义的配置源,借助 MapPropertySource
能够来实现咱们需要场景
1. 自定义数据源
演示一个最简略自定义的配置数据源,重写 MapPropertySource
的getProperties
办法
实现如下
public class SimplePropertiesSource extends MapPropertySource {public SimplePropertiesSource(String name, Map<String, Object> source) {super(name, source);
}
public SimplePropertiesSource() {this("filePropertiesSource", new HashMap<>());
}
/**
* 笼罩这个办法,实用于实时获取配置
*
* @param name
* @return
*/
@Override
public Object getProperty(String name) {
// 留神,只针对自定义结尾的配置才执行这个逻辑
if (name.startsWith("selfdefine.")) {return name + "_" + UUID.randomUUID();
}
return super.getProperty(name);
}
}
2. 数据源注册
下面只是申明了配置源,接下来把它注册到 Environment 中,这样就能够供给用应用了
@RestController
@SpringBootApplication
public class Application {
private Environment environment;
@Bean
public SimplePropertiesSource simplePropertiesSource(ConfigurableEnvironment environment) {
this.environment = environment;
SimplePropertiesSource ropertiesSource = new SimplePropertiesSource();
environment.getPropertySources().addLast(ropertiesSource);
return ropertiesSource;
}
// 获取配置
@GetMapping(path = "get")
public String getProperty(String key) {return environment.getProperty(key);
}
public static void main(String[] args) {SpringApplication.run(Application.class);
}
}
从下面的输入能够看出,自定义配置结尾的会获取到随机的配置值;非 selfdefine
结尾的,没有相应的配置,返回空
3. 基于文件的自定义配置源
下面这个可能有点过于儿戏了,接下来咱们将配置源放在自定义的文件中,并反对文件配置批改
public class FilePropertiesSource extends MapPropertySource {public FilePropertiesSource(String name, Map<String, Object> source) {super(name, source);
}
public FilePropertiesSource() {this("filePropertiesSource", new HashMap<>());
}
// 这种形式,实用于一次捞取所有的配置,而后从内存中查问对应的配置,进步服务性能
// 10s 更新一次
@PostConstruct
@Scheduled(fixedRate = 10_000)
public void refreshSource() throws IOException {
String ans =
FileCopyUtils.copyToString(new InputStreamReader(FilePropertiesSource.class.getClassLoader().getResourceAsStream("kv.properties")));
Map<String, Object> map = new HashMap<>();
for (String sub : ans.split("\n")) {if (sub.isEmpty()) {continue;}
String[] kv = StringUtils.split(sub, "=");
if (kv.length != 2) {continue;}
map.put(kv[0].trim(), kv[1].trim());
}
source.clear();
source.putAll(map);
}
}
下面写了一个定时器,每 10s 刷新一下内存中的配置信息,当然这里也是能够配置一个文件变动监听器,相干有趣味的话,能够看下 Java 实现文件变动的监听能够怎么玩
对应的配置文件
user=xhh
name= 一灰灰
age=18
注册的姿态与下面统一,就不独自阐明了,接下来演示一下应用
从上能够看到文件中的配置批改之后,过一段时间会刷新
4. @Value
绑定自定义配置
接下来咱们看一下,将 @Value
绑定自定义的配置,是否能够胜利
调整一下下面的 Application, 增加一个成员属性
@Value("${name}")
private String name;
@GetMapping(path = "get")
public String getProperty(String key) {return name + "|" + environment.getProperty(key);
}
再次测试发现抛异样了,说是这个配置不存在!!!
(这就过分了啊,看了半天,后果通知我不行,这还不得连忙搞个差评么 😡😡😡)
曾经写到这里了,当然我也得持续尝试解救一下,为啥后面间接通过 Environment
能够拿到配置,然而 @Value
注解绑定就不行呢?
”罪魁祸首“就在于初始化程序,我自定义的配置源,还没有塞到Envrionment
,你就散会着手绑定了,就像筹备给”一灰灰 blog“一个差评,后果发现还没关注 …(好吧,我抵赖没关注也能够评论 😭)
依据既往的知识点(至于是哪些知识点,那就长话短说不了了,看上面几篇精选的博文吧)
- 【SpringBoot 根底系列 - 实战】如何指定 bean 最先加载(利用篇)
- SpringBoot 系列教程之 Bean 之指定初始化程序的若干姿态
- SpringBoot 系列教程之 Bean 加载程序之谬误应用姿态造谣
要解决这个问题,一个最简略的形式如下
创立一个独立的配置类,实现自定义数据源的注册
@Configuration
public class AutoConfig {
@Bean
public FilePropertiesSource filePropertiesSource(ConfigurableEnvironment environment) {FilePropertiesSource filePropertiesSource = new FilePropertiesSource();
environment.getPropertySources().addLast(filePropertiesSource);
return filePropertiesSource;
}
}
测试类上指定 bean 依赖
@DependsOn("filePropertiesSource")
@EnableScheduling
@RestController
@SpringBootApplication
public class Application {
@Autowired
private Environment environment;
@Value("${name}")
private String name;
@GetMapping(path = "get")
public String getProperty(String key) {return name + "|" + environment.getProperty(key);
}
public static void main(String[] args) {SpringApplication.run(Application.class);
}
}
再次测试,后果如下
从下面的演示动图能够看到,绑定自定义的数据源配置,没有问题,然而,当配置变更时,绑定的 name 字段,没有随之更新
简略来讲就是不反对动静刷新,这就好受了啊,我就想要动静刷新,那该怎么搞?
- 不要急,新的博文曾经安顿上了,下篇奉上(怕迷路的小伙伴,无妨关注一下”一灰灰 blog“🐺)
5. 小结
最初依照常规小结一下,本文篇幅虽长,但知识点比拟集中,总结下来,两句话搞定
- 通过继承
MapPropertySource
来实现自定义配置源,注册到Envrionment
可供@Value
应用 - 应用
@Value
绑定自定义配置源时,留神注册的程序要早于 bean 的初始化
好的,到这里注释完结,我是一灰灰,欢送各位大佬来踩一踩长草的公众号 ” 一灰灰 blog”
III. 不能错过的源码和相干知识点
0. 我的项目
- 工程:https://github.com/liuyueyi/spring-boot-demo
- 源码: https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/002-dynamic-envronment
配置系列博文
- 【SpringBoot 根底系列】@Value 中哪些你不晓得的知识点
- 【SpringBoot 根底系列】ConfigurationProperties 配置绑定中那些你不晓得的事件
- 【SpringBoot 根底系列】PropertySource 加载 Yaml 配置文件实例演示
- 【SpringBoot 根底系列】实现一个自定义配置加载器(利用篇)
- SpringBoot 根底篇配置信息之配置刷新
- SpringBoot 根底篇配置信息之自定义配置指定与配置内援用
- SpringBoot 根底篇配置信息之多环境配置信息
- SpringBoot 根底篇配置信息之如何读取配置信息
1. 一灰灰 Blog
尽信书则不如,以上内容,纯属一家之言,因集体能力无限,不免有疏漏和谬误之处,如发现 bug 或者有更好的倡议,欢送批评指正,不吝感谢
上面一灰灰的集体博客,记录所有学习和工作中的博文,欢送大家前去逛逛
- 一灰灰 Blog 集体博客 https://blog.hhui.top
- 一灰灰 Blog-Spring 专题博客 http://spring.hhui.top