一灰灰blog 一灰灰blog
首页
  • InfluxDB
  • MongoDB
  • MySql
  • 基础系列
  • DB系列
  • 搜索系列
  • MQ系列
  • WEB系列
  • 中间件
  • 运维
  • SpringSecurity
  • SpringCloud
  • QuickAlarm
  • QuickCrawer
  • QuickFix
  • QuickMedia
  • QuickSpi
  • QuickTask
  • 高可用
  • 分类
  • 标签
  • 归档
  • 收藏
  • 关于
GitHub (opens new window)

一灰灰blog

资深搬运工
首页
  • InfluxDB
  • MongoDB
  • MySql
  • 基础系列
  • DB系列
  • 搜索系列
  • MQ系列
  • WEB系列
  • 中间件
  • 运维
  • SpringSecurity
  • SpringCloud
  • QuickAlarm
  • QuickCrawer
  • QuickFix
  • QuickMedia
  • QuickSpi
  • QuickTask
  • 高可用
  • 分类
  • 标签
  • 归档
  • 收藏
  • 关于
GitHub (opens new window)
  • 基础系列

    • 配置

      • 【基础系列】SpringBoot基础篇配置信息之如何读取配置信息
      • 【基础系列】SpringBoot基础篇配置信息之多环境配置信息
      • 【基础系列】SpringBoot基础篇配置信息之自定义配置指定与配置内引用
      • 【基础系列】SpringBoot配置信息之配置刷新
      • 【基础系列】SpringBoot配置信息之默认配置
      • 【基础系列】实现一个自定义配置加载器(应用篇)
      • 【基础系列】SpringBoot配置篇之PropertySource加载Yaml配置文件实例演示
      • 【基础系列】ConfigurationProperties配置绑定中那些你不知道的事情
      • 【基础系列】SpringBoot基础篇@Value中哪些你不知道的知识点
      • 【基础系列】SpringBoot之自定义配置源的使用姿势
        • I. 项目环境
          • 1. 项目依赖
        • II. 自定义配置源
          • 1. 自定义数据源
          • 2. 数据源注册
          • 3. 基于文件的自定义配置源
          • 4. @Value绑定自定义配置
          • 5. 小结
        • III. 不能错过的源码和相关知识点
          • 0. 项目
          • 1. 一灰灰Blog
      • 【基础系列】SpringBoot @Value之字面量及SpEL知识点介绍篇
      • 【基础系列】SpringBoot应用篇@Value注解支持配置自动刷新能力扩展
      • 【基础系列】基于maven多环境配置
    • AOP

    • Bean

    • SpEL

    • 事件

    • 国际化

    • 定时器

    • 日志

  • DB系列

  • 搜索系列

  • MQ系列

  • WEB系列

  • 中间件

  • 运维

  • SpringSecurity

  • SpringCloud

  • Spring系列
  • 基础系列
  • 配置
一灰灰
2021-06-10

【基础系列】SpringBoot之自定义配置源的使用姿势

前面一篇博文介绍了一个@Value的一些知识点,其中提了一个点,@Value对应的配置,除了是配置文件中之外,可以从其他的数据源中获取么,如从redis,db,http中获取配置?

了解过SpringCloud Config的可以给出确切的答案,可以,而且用起来还老爽了,远程配置,支持配置动态刷新,接下来我们来看一下,在SpringBoot中,如何配置自定义的数据源

# 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>
1
2
3
4
5
6

# 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);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

# 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);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

从上面的输出可以看出,自定义配置开头的会获取到随机的配置值;非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);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

上面写了一个定时器,每10s刷新一下内存中的配置信息,当然这里也是可以配置一个文件变动监听器,相关有兴趣的话,可以看下Java实现文件变动的监听可以怎么玩 (opens new window)

对应的配置文件

user=xhh
name=一灰灰
age=18
1
2
3

注册的姿势与上面一致,就不单独说明了,接下来演示一下使用

从上可以看到文件中的配置修改之后,过一段时间会刷新

# 4. @Value绑定自定义配置

接下来我们看一下,将@Value绑定自定义的配置,是否可以成功

调整一下上面的Application, 添加一个成员属性

@Value("${name}")
private String name;

@GetMapping(path = "get")
public String getProperty(String key) {
    return name + "|" + environment.getProperty(key);
}
1
2
3
4
5
6
7

再次测试发现抛异常了,说是这个配置不存在!!!

(这就过分了啊,看了半天,结果告诉我不行,这还不得赶紧搞个差评么😡😡😡)

已经写到这里了,当然我也得继续尝试挽救一下,为啥前面直接通过Environment可以拿到配置,但是@Value注解绑定就不行呢?

”罪魁祸首“就在于初始化顺序,我自定义的配置源,还没有塞到Envrionment,你就开会着手绑定了,就像准备给”一灰灰blog“一个差评,结果发现还没关注...(好吧,我承认没关注也可以评论😭)

根据既往的知识点(至于是哪些知识点,那就长话短说不了了,看下面几篇精选的博文吧)

  • 【SpringBoot基础系列-实战】如何指定 bean 最先加载(应用篇) (opens new window)
  • SpringBoot系列教程之Bean之指定初始化顺序的若干姿势 (opens new window)
  • SpringBoot系列教程之Bean加载顺序之错误使用姿势辟谣 (opens new window)

要解决这个问题,一个最简单的方式如下

创建一个独立的配置类,实现自定义数据源的注册

@Configuration
public class AutoConfig {
    @Bean
    public FilePropertiesSource filePropertiesSource(ConfigurableEnvironment environment) {
        FilePropertiesSource filePropertiesSource = new FilePropertiesSource();
        environment.getPropertySources().addLast(filePropertiesSource);
        return filePropertiesSource;
    }
}
1
2
3
4
5
6
7
8
9

测试类上指定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);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

再次测试,结果如下

从上面的演示动图可以看到,绑定自定义的数据源配置,没有问题,但是,当配置变更时,绑定的name字段,没有随之更新

简单来讲就是不支持动态刷新,这就难受了啊,我就想要动态刷新,那该怎么搞?

  • 不要急,新的博文已经安排上了,下篇奉上(怕迷路的小伙伴,不妨关注一下”一灰灰blog“🐺)

# 5. 小结

最后按照惯例小结一下,本文篇幅虽长,但知识点比较集中,总结下来,两句话搞定

  • 通过继承MapPropertySource来实现自定义配置源,注册到Envrionment可供@Value使用
  • 使用@Value绑定自定义配置源时,注意注册的顺序要早于bean的初始化

好的,到这里正文结束, 我是一灰灰,欢迎各位大佬来踩一踩长草的公众号"一灰灰blog"

# III. 不能错过的源码和相关知识点

# 0. 项目

  • 工程:https://github.com/liuyueyi/spring-boot-demo (opens new window)
  • 源码: https://github.com/liuyueyi/spring-boot-demo/tree/master/spring-boot/002-dynamic-envronment (opens new window)

配置系列博文

  • 【SpringBoot 基础系列】@Value 中哪些你不知道的知识点 (opens new window)
  • 【SpringBoot 基础系列】ConfigurationProperties 配置绑定中那些你不知道的事情 (opens new window)
  • 【SpringBoot 基础系列】SpringBoot 配置篇之 PropertySource 加载 Yaml 配置文件实例演示 (opens new window)
  • 【SpringBoot 基础系列】实现一个自定义配置加载器(应用篇) (opens new window)
  • SpringBoot基础篇配置信息之配置刷新 (opens new window)
  • SpringBoot基础篇配置信息之自定义配置指定与配置内引用 (opens new window)
  • SpringBoot基础篇配置信息之多环境配置信息 (opens new window)
  • SpringBoot基础篇配置信息之如何读取配置信息 (opens new window)

# 1. 一灰灰Blog

尽信书则不如,以上内容,纯属一家之言,因个人能力有限,难免有疏漏和错误之处,如发现bug或者有更好的建议,欢迎批评指正,不吝感激

下面一灰灰的个人博客,记录所有学习和工作中的博文,欢迎大家前去逛逛

  • 一灰灰Blog个人博客 https://blog.hhui.top (opens new window)
  • 一灰灰Blog-Spring专题博客 http://spring.hhui.top (opens new window)

一灰灰blog

编辑 (opens new window)
#Value
上次更新: 2021/10/15, 19:56:22
【基础系列】SpringBoot基础篇@Value中哪些你不知道的知识点
【基础系列】SpringBoot @Value之字面量及SpEL知识点介绍篇

← 【基础系列】SpringBoot基础篇@Value中哪些你不知道的知识点 【基础系列】SpringBoot @Value之字面量及SpEL知识点介绍篇→

最近更新
01
【基础系列】基于maven多环境配置
04-25
02
【WEB系列】内嵌Tomcat配置Accesslog日志文件生成位置源码探索
04-24
03
【搜索系列】ES查询常用实例演示
04-18
更多文章>
Theme by Vdoing | Copyright © 2017-2022 一灰灰Blog
MIT License | 鄂ICP备18017282号 |
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×