目标

Java 程序维护一个全局的配置对象,可以在任何地方读取配置文件 application.properties 中的配置。项目启动后,从配置文件中读取配置并创建对象实例,之后就可以集中地从这个对象中获取配置信息,而不用每次加载配置时再重新读取配置、并创建新的对象,减少了性能开销。

代码实践

项目初始化与依赖引入

新建空 Maven 项目。pom.xml 引入以下依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.32</version>
<scope>provided</scope>
</dependency>
<!-- https://doc.hutool.cn/ -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/ch.qos.logback/logback-classic -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.3.12</version>
</dependency>
</dependencies>

本项目使用 Hutool 工具类简化代码的编写。

配置类

这个类定义了你的 Java 应用的默认配置。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package top.uuanqin.glocalconfig.config;

import lombok.Data;

/**
* 我的应用配置
* @author uuanqin
*/
@Data
public class MyConfig {

/**
* 姓名
*/
private String name = "Wuanqin";

/**
* ID
*/
private Integer id = 10908;

}

配置加载工具类

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
34
35
36
37
38
39
40
41
42
package top.uuanqin.glocalconfig.config;

import cn.hutool.core.util.StrUtil;
import cn.hutool.setting.dialect.Props;

/**
* 配置工具类
*/
public class ConfigUtils {

/**
* 加载配置对象
*
* @param tClass
* @param prefix
* @param <T>
* @return
*/
public static <T> T loadConfig(Class<T> tClass, String prefix) {
return loadConfig(tClass, prefix, "");
}

/**
* 加载配置对象,支持区分环境
*
* @param tClass
* @param prefix
* @param environment
* @param <T>
* @return
*/
public static <T> T loadConfig(Class<T> tClass, String prefix, String environment) {
StringBuilder configFileBuilder = new StringBuilder("application");
if (StrUtil.isNotBlank(environment)) {
configFileBuilder.append("-").append(environment);
}
configFileBuilder.append(".properties");
Props props = new Props(configFileBuilder.toString());
return props.toBean(tClass, prefix);
}
}

这个工具类的作用是,传入配置类、配置名称的前缀以及环境,返回填好配置信息的配置类。

Hutool 中的 Props
  • 类 Props:Properties 文件读取封装类。继承 java.util.Properties
  • 构造函数:Props(String path) 构造,使用相对于 Class 文件根目录的相对路径。
  • 方法 <T> T toBean(Class<T> beanClass, String prefix):将配置文件转换为 Bean,支持嵌套 Bean。
    - prefix:公共前缀,不指定前缀传 null,当指定前缀后非此前缀的属性被忽略

——hutool 5.8.29 API

Hutool 中的 StrUtil 工具类
  • 继承 cn.hutool.core.text.CharSequenceUtil
  • CharSequenceUtil 中的方法:isNotBlank(CharSequence str)。判断字符串是否为非空白,非空白的定义如下: 不为 null 不为空字符串:"" 不为空格、全角空格、制表符、换行符,等不可见字符

——hutool 5.8.29 API

这个工具类的亮点在于:

  1. 灵活处理配置类,loadConfigtClass 参数指定生成的配置类
  2. 多环境配置文件的支持:通过 environment 参数,依照命名惯例,加载多环境的配置文件
  3. 可拓展点:你可以试着编写读取 application.yaml 配置的功能

关于 java.util.Properties 更多说明详见:java.util.Properties类操作properties文件-CSDN博客

关于 getBean 函数可看本站文章以获取更多补充:SpringBoot 中的 IOC & DI 入门

常量定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package top.uuanqin.glocalconfig.config;

/**
* 相关常量
*
*/
public interface Constant {

/**
* 默认配置文件加载前缀
*/
String DEFAULT_CONFIG_PREFIX = "my-config";
}

使用单例模式维护全局对象

这里的单例模式使用了经典的双检锁单例模式。

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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package top.uuanqin.glocalconfig;


import lombok.extern.slf4j.Slf4j;
import top.uuanqin.glocalconfig.config.ConfigUtils;
import top.uuanqin.glocalconfig.config.Constant;
import top.uuanqin.glocalconfig.config.MyConfig;

/**
* 我的应用
* 相当于 holder,存放了项目全局用到的变量。双检锁单例模式实现
* @author uuanqin
*/
@Slf4j
public class MyApplication {

private static volatile MyConfig myConfig;

/**
* 框架初始化,支持传入自定义配置
*
* @param newMyConfig
*/
public static void init(MyConfig newMyConfig) {
myConfig = newMyConfig;
log.info("my application init, config = {}", newMyConfig.toString());
}

/**
* 初始化
*/
public static void init() {
MyConfig newMyConfig;
try {
newMyConfig = ConfigUtils.loadConfig(MyConfig.class, Constant.DEFAULT_CONFIG_PREFIX);
} catch (Exception e) {
// 配置加载失败,使用默认值
newMyConfig = new MyConfig();
}
init(newMyConfig);
}

/**
* 获取配置
*
* @return
*/
public static MyConfig getMyConfig() {
if (myConfig == null) {
synchronized (MyApplication.class) {
if (myConfig == null) {
init();
}
}
}
return myConfig;
}
}

为了便于扩展,支持通过 public static void init(MyConfig newMyConfig) 方法传入自己的配置。

测试

调用测试

一行代码即可读取配置。

1
2
3
4
5
6
7
8
9
10
package top.uuanqin.glocalconfig;

import top.uuanqin.glocalconfig.config.MyConfig;

public class Main {
public static void main(String[] args) {
MyConfig config = MyApplication.getMyConfig();
}
}

修改配置文件

修改配置文件运行测试可以查看效果。

application.properties

1
my-config.id=6651

本文参考