Records : 385
Scenario : In Spring Boot microservices, read application.yml or bootstrap.yml and other yml file configurations, convert them to Map<String, Object> storage, use (key, value) key-value pairs, and use them out of the box.
1. Basic description
1.1 Reasons for conversion
Use the org.yaml.snakeyaml.Yaml of the snakeyaml framework to load the yml file from the ../src/main/resources resource of the microservice, and store it in Map<String, Object> mapFromYml.
(1) yml file configuration example
server:
servlet:
context-path: /hub-example
spring:
jackson:
time-zone: GMT+8
(2) Yaml loading Map storage method
Yaml loads Map storage method: According to the yml file format, a character string before a colon is a key of a Map, and the part after a colon is a Map, until the colon is followed by a specific value, it is a specific Object. Therefore, the result Map<String, Object> loaded by Yaml has many layers of Maps nested in it, and the value of the last layer of Maps is the specific value. For the specific format, please refer to the figure below.
Insufficient usage: The (key, value) key-value pair of the Map loaded by Yaml cannot be used directly, and it needs to traverse multiple times to find the final value. Therefore, conversion is required.
(3) Convert the Map loaded by Yaml into a Map that can be used directly
yml configuration example:
server:
servlet:
context-path: /hub-example
spring:
jackson:
time-zone: GMT+8
Storage method after conversion:
spring.jackson.time-zone=GMT+8
server.servlet.context-path=/hub-example
How to get value after conversion:
Object value = Map.get(“spring.jackson.time-zone”)
1.2 Core dependencies
(1) Function
Load the yml file using the snakeyaml framework.
(2) Dependent packages
jar包:snakeyaml-1.33.jar
pom.xml depends on:
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>1.33</version>
</dependency>
2. Example 1: Read the yml configuration and convert it to Map<String, Object> according to the yml file name
2.1 Implementation method
//1.从yml文件中加载
public static Map<String, Object> loadFromYmlFile(String ymlFileName) {
InputStream input = null;
Map<String, Object> mapFromYml = null;
if (StringUtils.isBlank(ymlFileName)) {
return null;
}
try {
ClassPathResource resource = new ClassPathResource(ymlFileName);
input = resource.getInputStream();
Yaml yaml = new Yaml();
mapFromYml = yaml.loadAs(input, Map.class);
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
return mapFromYml;
}
//2.第一层转换
public static Map<String, Object> convertYml(Map<String, Object> mapFromYml) {
Map<String, Object> map = mapFromYml;
Map<String, Object> mapAfterConvert = new HashMap<>();
map.forEach((key1, value1) -> {
if (value1 instanceof Map) {
mapAfterConvert.putAll(forEachYml(mapAfterConvert, key1, (Map) value1));
} else {
mapAfterConvert.put(key1, value1.toString());
}
});
mapAfterConvert.forEach((key,value)->{
System.out.println(key+"="+value);
});
return mapAfterConvert;
}
// 3.第二层转换(递归转换)
public static Map<String, Object> forEachYml(Map<String, Object> mapAfterConvert, String key1, Map<String, Object> map) {
map.forEach((key2, value2) -> {
String strNew;
if (StringUtils.isNotEmpty(key1)) {
strNew = key1 + "." + key2;
} else {
strNew = key2;
}
if (value2 instanceof Map) {
mapAfterConvert.putAll(forEachYml(mapAfterConvert, strNew, (Map) value2));
} else {
mapAfterConvert.put(strNew, value2);
}
});
return mapAfterConvert;
}
// 4.转换为(key,value),直接使用版本
public static Map<String, Object> getYmlAllConfig(String ymlFileName) {
return convertYml(loadFromYmlFile(ymlFileName));
}
2.2 Test method
public static void main(String[] args) {
Map<String, Object> application = getYmlAllConfig("application.yml");
}
3. Example 2: Read the yml file and use the singleton method to store the conversion result Map<String, Object>
3.1 Implementation method
public final class YmlFileUtil02 {
private static YmlFileUtil02 ymlFileUtil = null;
private String ymlFileName = "application.yml";
// org.yaml.snakeyaml.Yaml从yml文件加载的Map(需逐层遍历才能定位到具体值)
private Map<String, Object> mapFromYml = new HashMap<>();
// 转换后的Map,直接使用getValue(key)获取值
private Map<String, Object> mapAfterConvert = new HashMap<>();
//从yml文件中加载与转换
private YmlFileUtil02(String ymlFileName) {
InputStream input = null;
if (StringUtils.isNotBlank(ymlFileName)) {
this.ymlFileName = ymlFileName;
}
try {
ClassPathResource resource = new ClassPathResource(this.ymlFileName);
input = resource.getInputStream();
Yaml yaml = new Yaml();
this.mapFromYml = yaml.loadAs(input, Map.class);
convertYml();
} catch (Exception e) {
e.printStackTrace();
} finally {
if (input != null) {
try {
input.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
// 第一层转换
private void convertYml() {
Map<String, Object> map = this.mapFromYml;
map.forEach((key1, value1) -> {
if (value1 instanceof Map) {
this.mapAfterConvert.putAll(forEachYml(key1, (Map) value1));
} else {
this.mapAfterConvert.put(key1, value1.toString());
}
});
}
// 第二层转换(递归转换)
private Map<String, Object> forEachYml(String key1, Map<String, Object> map) {
map.forEach((key2, value2) -> {
String strNew;
if (StringUtils.isNotEmpty(key1)) {
strNew = key1 + "." + key2;
} else {
strNew = key2;
}
if (value2 instanceof Map) {
this.mapAfterConvert.putAll(this.forEachYml(strNew, (Map) value2));
} else {
this.mapAfterConvert.put(strNew, value2);
}
});
return this.mapAfterConvert;
}
// 转换为(key,value),直接使用
public Object getValue(String key) {
return this.mapAfterConvert.get(key);
}
// 根据文件名创建单例对象
public static YmlFileUtil02 getInstance(String ymlFileName) {
if (ymlFileUtil == null) {
Class<YmlFileUtil02> obj = YmlFileUtil02.class;
synchronized (obj) {
if (ymlFileUtil == null) {
ymlFileUtil = new YmlFileUtil02(ymlFileName);
}
}
}
return ymlFileUtil;
}
}
3.2 Test method
public static void main(String[] args) {
YmlFileUtil02 ymlInstance = YmlFileUtil02.getInstance("application.yml");
System.out.println("server.port=" + ymlInstance.getValue("server.port"));
System.out.println("spring.jackson.time-zone=" + ymlInstance.getValue("spring.jackson.time-zone"));
}
4. Test the yml file
4.1 File name
application.yml
4.2 File content
server:
servlet:
context-path: /hub-example
port: 18080
spring:
jackson:
time-zone: GMT+8
application:
name: hub-example-custom
cloud:
nacos:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
namespace: d4f554cb-941e-40bc-85ce-f7a16c0dd4ba
config:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
namespace: d4f554cb-941e-40bc-85ce-f7a16c0dd4ce
group: DEFAULT_GROUP
file-extension: yaml
shared-configs:
- dataId: hub01.yml
refresh: true
group: DEFAULT_GROUP
- dataId: hub02.yml
refresh: true
group: DEFAULT_GROUP
- dataId: hub03.yml
refresh: true
group: DEFAULT_GROUP
4.3 Precautions
In the yml file, the configuration starting with -dash corresponds to the Java object being of List type. So the (key, value) of this class looks like this:
key=spring.cloud.config.shared-configs
value=ArrayList
Above, thanks.
March 13, 2023