概述
之前介绍过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