前言
上一节我们通过注解@PropertySource读取内外部配置文件,然后通过注解@Value读取其值,在Spring中通过注解@ConfigurationProperties也可以读取配置文件中的值,接下来我们一起来看看注解@ConfigurationProperties和@Value有何区别。
@ConfigurationProperties VS @Value注解
关于注解@Value上一节我们已经详细讨论过,那么我们首先来分析注解@ConfigurationProperties,接下来我们在配置文件application.properties中给出一段我们需要读取的值,如下:
#app app.trade-currency=USD app.refresh-time-unit=seconds app.refresh-rate=3
接下来我们在创建的配置文件类Spring.Config中来读取值,如下:
package com.demo.springboot; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.Currency; import java.util.concurrent.TimeUnit; @Configuration @ConfigurationProperties(prefix = "app") public class SpringConfig { private int refreshRate; private TimeUnit refreshTimeUnit; private Currency tradeCurrency; @Bean public UserDAL getUserDAL() { return new UserDAL(); } @Override public String toString() { System.out.println(); return "SpringConfig:{" + "refreshRate = '" + refreshRate + '\'' + ", refreshTimeUnit = '" + refreshTimeUnit + '\'' + ", tradeCurrency = '" + tradeCurrency + '\'' + '}'; } }
如上我们并未添加注解@PropertySource指定读取文件位置,因为默认会从默认创建的配置文件application.properties中读取。注解@ConfigurationProperties需要明确参数prefix(前缀),而且不能为空,我们看到在配置文件中所给出的值的前缀都为app,所以如上我们给出其参数前缀为app,接下来我们调用该配置文件类并打印出映射结果,如下:
package com.demo.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.ConfigurableApplicationContext; @SpringBootApplication public class SpringbootApplication { public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(SpringbootApplication.class, args); SpringConfig bean = context.getBean(SpringConfig.class); System.out.println(bean); } }
如上我们可以看到值都为默认值并未映射上,这是为什么呢?因为通过注解@ConfigurationProperties绑定字段时,必须要使用属性。如下我们添加属性:
public int getRefreshRate() { return refreshRate; } public void setRefreshRate(int refreshRate) { this.refreshRate = refreshRate; } public TimeUnit getRefreshTimeUnit() { return refreshTimeUnit; } public void setRefreshTimeUnit(TimeUnit refreshTimeUnit) { this.refreshTimeUnit = refreshTimeUnit; } public Currency getTradeCurrency() { return tradeCurrency; } public void setTradeCurrency(Currency tradeCurrency) { this.tradeCurrency = tradeCurrency; }
既然注解@ConfigurationProperties通过属性来绑定,那么对于我们在配置文件中的名称是否有大小写要求或者说必须精确匹配呢? 注解@ConfigurationProperties对属性绑定遵循relaxed bind rule【暂且翻译为松散绑定规则】,并不需要精确匹配。比如对属性【app.username】,通过【app.userName】、【app.user-name】、【app.user_name】、【app.USER_NAME】、【app.USER-NAME】等都可匹配,我们可理解为模糊匹配。上述我们看到时间值我们声明的是小写,但最终翻译成了大写,但是对于上述货币而言,我们必须定义成大写,在配置文件中不能定义成小写或者大小写混用,比如在配置文件中我们声明其值为usd,否则将抛出如下异常。
对于注解@Value而言,占位符必须严格和配置文件中对应键一致,否则抛出无法解析异常。到此我们可以知道若一个类中有很多字段,那么必须在每一个字段上都添加@Value注解,如此一来比较繁琐,对少数字段还是比较友好,其实呢应该推荐使用注解@ConfigurationProperties,因为少数字段映射我们完全可借助注解@Environment接口获取。一言以蔽之,我们总结下注解@ConfigurationProperties和@Value的区别: @ConfigurationProperties用于使用POJO bean映射属性,而注解@Value通过键注入特定的属性值。
总结
本节我们重点讨论了注解@ConfigurationProperties的使用,对于批量属性映射POJO,很明显会通过注解@ConfigurationProperties操作,相对注解@Value而言,它更加灵活,我想这也是推荐使用该注解的原因,好了,本节我们到此为止,感谢您的阅读,我们下节见。