概述
之前介绍过Spring中的配置类@Configuration,在配置类中通过注入Environment或者@Value,我们可以拿到外部配置数据。在Spring boot中,框架默认提供了application,properties配置文件来提供系统配置,那么有没有更好的办法来获取外部配置呢? 那就是@ConfigurationProperties。
应用示例
1、我们在类路径下新建一个配置文件:test.properties
test.data
=
hello
test.num
=
10
2、新建配置属性文件:
AppConfigProperties.java
@ConfigurationProperties
(prefix =
"test"
,locations =
"classpath:test.properties"
)
public class
AppConfigProperties {
private
String
data
;
private int
num
;
//忽略getter & setter
}
我们来看注解使用的参数,prefix代表配置前缀,前缀和属性名称对应于配置文件的key,容器会自动绑定配置文件的数据到对应的配置属性类中。locations 属性指向了配置文件的路径。
3、新建配置类:
AppConfig.java
@Configuration
@EnableConfigurationProperties
(AppConfigProperties.
class
)
public class
AppConfig {
@Autowired
public
AppConfigProperties
properties
;
}
我们在配置类中使用了
@EnableConfigurationProperties来激活配置属性,注解的属性申明了配置属性类
AppConfigProperties.
class,最后我们只要把
AppConfig注册到应用上下文即可。
4、测试主类:
AnnotationConfigApplicationContext context =
new
AnnotationConfigApplicationContext();
context.register(AppConfig.
class
);
context.refresh();
AppConfig appConfig = context.getBean(AppConfig.
class
);
System.
out
.println(appConfig.
properties
.getData());
System.
out
.println(appConfig.
properties
.getNum());
就可以直接访问到属性配置绑定之后的数据了。
@ConfigurationProperties源码解析
现在让我们来抽丝剥茧,看看整个配置属性类和数据绑定是如何工作的。先看一下@ConfigurationProperties的源码:
@Target
({ ElementType.
TYPE
, ElementType.
METHOD
})
@Retention
(RetentionPolicy.
RUNTIME
)
@Documented
public
@
interface
ConfigurationProperties
{
@AliasFor
(
"prefix"
) //前缀,互为别名
String value()
default
""
;
@AliasFor
(
"value"
) //前缀,互为别名
String prefix()
default
""
;
// 是否忽略非法的属性,通常指类型不匹配,无法绑定数据到成员
boolean
ignoreInvalidFields()
default false
;
// 是否忽略嵌套的数据
boolean
ignoreNestedProperties()
default false
;
// 是否忽略未知的属性
boolean
ignoreUnknownFields()
default true
;
// 非法属性是否抛出异常
boolean
exceptionIfInvalid()
default true
;
// 搜速路径,因改为使用environment的路径,所以被标记过期
@Deprecated
String[] locations()
default
{};
// 是否和默认的配置项合并
@Deprecated
boolean
merge()
default true
;
}
除了最常用的prefix前缀配置,其它属性通常保持默认即可。
神奇的@EnableConfigurationProperties
不像之前的@Configuration配置注解,@ConfigurationProperties注解并没有@Component元注解,因此直接注册配置属性类并不会有任何效果。例如执行下面的代码:
AnnotationConfigApplicationContext context =
new
AnnotationConfigApplicationContext();
context.register(AppConfigProperties.
class
);
context.refresh();
AppConfigProperties appConfigProperties = context.getBean(AppConfigProperties.
class
);
--null
--0
只会创建普通的bean实例,上下文默认不会去解析注解,也不会做响应的数据绑定。真正的秘密隐藏在
@EnableConfigurationProperties里面,我们来调整一下上面的例子:
@ConfigurationProperties
(prefix =
"test"
,locations =
"classpath:test.properties"
)
@EnableConfigurationProperties
public class
AppConfigProperties {
private
String
data
;
private int
num
;
//忽略getter & setter
}
再执行上面的代码:
AnnotationConfigApplicationContext context =
new
AnnotationConfigApplicationContext();
context.register(AppConfigProperties.
class
);
context.refresh();
AppConfigProperties appConfigProperties = context.getBean(AppConfigProperties.
class
);
--hello
--10
发现配置数据正确的绑定到了配置属性对象。从注解名字Enable也可以看出,这个注解是一个开关注解,从而启用了对所有标注
@ConfigurationProperties的数据绑定处理。开关注解仅需执行一次即可,例如我们可以新建一个类
EnableSwitch.java
@EnableConfigurationProperties
()
public class
EnableSwitch
{
}
就算配置属性类没有标记
@EnableConfigurationProperties注解,之后加载所有标注
@ConfigurationProperties注解的bean都会正确绑定配置数据。
AnnotationConfigApplicationContext context =
new
AnnotationConfigApplicationContext();
context.register(EnableSwitch.
class
);
context.register(AppConfigProperties.
class
);
context.refresh();
AppConfigProperties appConfig = context.getBean(AppConfigProperties.
class
);
--hello
--10