上一节咱们经过注解@PropertySource读取内外部配置文件,而后经过注解@Value读取其值,在Spring中经过注解@ConfigurationProperties也能够读取配置文件中的值,接下来咱们一块儿来看看注解@ConfigurationProperties和@Value有何区别。java
关于注解@Value上一节咱们已经详细讨论过,那么咱们首先来分析注解@ConfigurationProperties,接下来咱们在配置文件application.properties中给出一段咱们须要读取的值,以下:spring
#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,接下来咱们调用该配置文件类并打印出映射结果,以下:springboot
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绑定字段时,必需要使用属性。以下咱们添加属性:app
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,不然将抛出以下异常。ide
对于注解@Value而言,占位符必须严格和配置文件中对应键一致,不然抛出没法解析异常。到此咱们能够知道若一个类中有不少字段,那么必须在每个字段上都添加@Value注解,如此一来比较繁琐,对少数字段仍是比较友好,其实呢应该推荐使用注解@ConfigurationProperties,由于少数字段映射咱们彻底可借助注解@Environment接口获取。一言以蔽之,咱们总结下注解@ConfigurationProperties和@Value的区别: @ConfigurationProperties用于使用POJO bean映射属性,而注解@Value经过键注入特定的属性值。this
上述咱们只是讨论了注解@ConfigurationProperties的使用方式,接下来咱们来探讨下该注解正确使用姿式,上述咱们在使用该注解时,咱们发现同时添加了注解@Configuration,要是咱们不添加会报错以下:spa
此时又多出一个注解@EnableConfigurationProperties,难道是在使用注解@ConfigurationProperties时,必须添加该注解,说明咱们要启用该注解或者添加注解@Component吗?显然不是这样,使用注解@Configuration说明咱们要使用bean, 咱们知道注解@ConfigurationProperties是进行POJO映射,因此是干净的一个原始实体,彻底不用再添加其余注解,这里报错咱们暂且无论,咱们改造以下:翻译
package com.demo.springboot; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.Currency; import java.util.concurrent.TimeUnit; @ConfigurationProperties(prefix = "app") public class SpringConfig { private int refreshRate; private TimeUnit refreshTimeUnit; private Currency tradeCurrency; 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; } @Override public String toString() { System.out.println(); return "SpringConfig:{" + "refreshRate = '" + refreshRate + '\'' + ", refreshTimeUnit = '" + refreshTimeUnit + '\'' + ", tradeCurrency = '" + tradeCurrency + '\'' + '}'; } }
假设上述是读取的是链接数据库的相关配置,接下来咱们建立以下类:3d
package com.demo.springboot; public class DbConnectionConfiguration { ...... }
咱们建立上述类要链接数据库并进行相关操做,此时则须要用到上述数据库配置类,此时就要用到注解@EnableConfigurationProperties,经过添加该注解表示要查找并注册注解为@ConfigurationProperties做为bean,同时呢咱们也要添加注解@Configuration提供进行数据源的bean,以下:
package com.demo.springboot; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration @EnableConfigurationProperties(SpringConfig.class) public class DbConnectionConfiguration { private SpringConfig springConfig; public DbConnectionConfiguration(SpringConfig springConfig) { this.springConfig = springConfig; } @Bean public DataSource dataSource() { ...... } }
此时咱们将发现Spring.Config再也不报错,由于上述咱们使用Spring.Config做为了一个bean,不然在开始时,咱们看到报错,立马添加注解@Component,接下来运行将抛出Spring.Config已屡次被注解为bean,以下:
Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: ...... available: expected single matching bean but found 2: springConfig,app-com.demo.springboot.SpringConfig
相信经过上述个人举例,阅读本文的您可以明白这几者的区别所在了,在这里呢,咱们能够下一个结论: 注解@ConfigurationProperties用于将类与外部属性配置文件绑定,由于其彻底属于POJO,因此必须将Bean类与配置实体类隔离开。而在这种状况下注解@Configuration用于建立配置POJO的Spring bean。@EnableConfigurationProperties用于在配置实体类和Spring配置之间建立绑定,以便在注入服务内部以后能够轻松地检索到对应属性。
本节咱们重点讨论了注解@ConfigurationProperties的使用,对于批量属性映射POJO,很明显会经过注解@ConfigurationProperties操做,相对注解@Value而言,它更加灵活,我想这也是推荐使用该注解的缘由,好了,本节咱们到此为止,感谢您的阅读,咱们下节见。