今天遇到如下需求:我需要将如下application.yml配置读取到相应的Properties配置文件中:
1
2
3
4
5
6
7
8
9
|
templates:
- template: "${beanClass}.ftl"
module: ${project.modules.server}
packet: ${packages.service}
packets-to-import:
- ${packages.request}
- ${packages.response}
|
这个非常难搞,因为@ConfigurationProperties
必须要指定一个前缀,而这个前缀有需要作为Properties的一个字段,几经折腾我开发了如下的代码:
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
|
@Data
@Component
public class TemplatesProperties implements ApplicationContextAware {
private List<Template> templates;
@Data
public static class Template {
/**
* 模板文件
*/
private String template;
/**
* 当前模板所属的模块
*/
private String module;
/**
* 当前模板生成的类所属的包
*/
private String packet;
/**
* 当前模板生成的类额外需要导入的包
*/
private List<String> packetsToImport;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//noinspection unchecked
templates = (List<Template>) applicationContext.getBean("templates");
}
@Configuration
public static class TemplatesPropertiesInternalConfiguration {
@Bean
@ConfigurationProperties(prefix = "templates")
public List<Template> templates(List<Template> templates) {
return templates;
}
}
}
|
这个利用了ConfigurationProperties可以放在方法上,为什么说解决这个问题是靠想象力呢,我查了很多资料,没有找到相关需求的解决方案,所以我自己观察@ConfigurationProperties
,发现它可以注解到方法上,所以我就大胆尝试并查找了一些资料,解决了这个需求。
为什么不在application.yml中再加一个字段呢?因为我有强迫症!
优化与遇到的问题
我想将上面的代码优化成下面的写法:
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
|
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TemplatesProperties {
private List<Template> templates;
@Data
public static class Template {
/**
* 模板文件
*/
private String template;
/**
* 当前模板所属的模块
*/
private String module;
/**
* 当前模板生成的类所属的包
*/
private String packet;
/**
* 当前模板生成的类额外需要导入的包
*/
private List<String> packetsToImport;
}
@Configuration
public static class TemplatesPropertiesInternalConfiguration {
@Bean
@ConfigurationProperties(prefix = "templates")
public TemplatesProperties templates(List<Template> templates) {
return new TemplatesProperties(templates);
}
}
}
|
但是我发现此时获取的templates是一个长度为零的数组,同时Idea提示无法注入templates,我对这个问题产生了兴趣,于是还原代码进行测试,我有如下收获:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//noinspection unchecked
tables = (List<Table>) applicationContext.getBean("tables");
System.out.println("");
}
@Configuration
public static class TablePropertiesConfiguration {
@Bean
@ConfigurationProperties(prefix = "tables")
public List<Table> tables(List<Table> tables) {
return tables;
}
}
|
上面这段代码的调用时序为:
tables = (List<Table>) applicationContext.getBean("tables");
return tables;
System.out.println("");
(我没有从上面的调用时序收获到任何有意思的东西,只是觉得有趣而已)
此时return tables;
返回的是一个疮毒为0的tables,所以说,我一顿操作猛如虎,最后发现对@ConfigurationProperties
用于方法上理解是错误的。加了@ConfigurationProperties
并不是说此时方法注入的Bean的属性是从配置文件中获取的,而是说此时@Bean
方法返回的东东是从配置文件获取的,所以正确的优化方法只能是下面的这种写法:
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
|
@Data
@Component
public class TableProperties implements ApplicationContextAware {
private List<Table> tables;
@Data
public static class Table {
/**
* 表逻辑名称
*/
private String logicName;
/**
* 对应的实体名称
*/
private String entityName;
/**
* 不需要生成的模板
*/
private List<String> templatesExclude;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//noinspection unchecked
tables = (List<Table>) applicationContext.getBean("tables");
System.out.println("");
}
@Configuration
public static class TablePropertiesConfiguration {
@Bean
@ConfigurationProperties(prefix = "tables")
public List<Table> tables() {
return new ArrayList<>(0);
}
}
}
|
相对一开始的写法,省去了@Bean
方法的方法参数,虽然只是小小的一点改动,但代表着对@ConfigurationProperties
更正确的理解。
参考资料
- Spring Boot中注解@ConfigurationProperties的三种使用场景