首先简单说一下两个注解之前的区别。
@Configurationproperties | @Value | |
功能 | 批量注入配置文件中的属性 | 每个属性单独注入 |
松散语法 | 支持 | 不支持 |
SpEL | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持 | 不支持 |
首先说一下功能上面,@Configurationproperties只需要在类上面标明,便可以针对该类的所有属性批量注入,而@Value却需要在每个属性上面单独注入。
其次,松散语法是指使用"-"或者"_"以及驼峰命名之间自动转变,@Value并不支持
SpEL语法和JSR303数据校验以及复杂类型封装就没有什么好说了的。
下面上代码,老样子,首先是pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.6.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>cc.acme_me</groupId> <artifactId>spring-boot-annotation</artifactId> <version>0.0.1-SNAPSHOT</version> <name>spring-boot-annotation</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>runtime</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
这次先把配置文件放在前面,使用properties来配置属性
server.port=8080 ################User################ user.id=1 user.user-name=admin user.email=springboot#acme-me.cc
这次少配置东西,少一点属性方便观察。
接着是Entity的User类
package cc.acme_me.springbootannotation.entity; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import javax.validation.constraints.Email; /** * User entity * * @author acme * @Component 标识注入Spring容器中(只有注入Spring容器才能使用) */ @Component public class User { @Value("${user.id}")//获取配置文件中的值 private Integer id; @Value("${user.user-name}")//获取配置文件中的值 //@Value("${user.userName}")//获取配置文件中的值 不支持 private String userName; @Value("123")//字面量直接注入 private String password; @Value("#{15*3}")//SpEL表达式 private Integer privilegeLevel; @Email//在@Value下并不生效 @Value("${user.email}")//获取邮件 private String email; @Override public String toString() { return "User{" + "id=" + id + ", userName='" + userName + '\'' + ", password='" + password + '\'' + ", privilegeLevel=" + privilegeLevel + ", email='" + email + '\'' + '}'; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getPrivilegeLevel() { return privilegeLevel; } public void setPrivilegeLevel(Integer privilegeLevel) { this.privilegeLevel = privilegeLevel; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
按照上面的内容我们运行测试类
package cc.acme_me.springbootannotation; import cc.acme_me.springbootannotation.entity.User; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest public class SpringBootAnnotationApplicationTests { @Autowired private User user; @Test public void contextLoads() { System.out.println(user); } }
会发现测试通过了,可以看到这里emal的值并不是一个正确的邮箱地址,说明@Email校验在@Value下并未生效。
现在我们将User进行修改,使用@
package cc.acme_me.springbootannotation.entity; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import org.springframework.validation.annotation.Validated; import javax.validation.constraints.Email; /** * User entity * * @author acme * @ConfigurationProperties 注解用于标识注释参数 prefix标识对应的前缀 * @Component 标识注入Spring容器中(只有注入Spring容器才能使用) */ @ConfigurationProperties(prefix = "user") @Validated @Component public class User { private Integer id; private String userName; private String password; private Integer privilegeLevel; @Email private String email; @Override public String toString() { return "User{" + "id=" + id + ", userName='" + userName + '\'' + ", password='" + password + '\'' + ", privilegeLevel=" + privilegeLevel + ", email='" + email + '\'' + '}'; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getPrivilegeLevel() { return privilegeLevel; } public void setPrivilegeLevel(Integer privilegeLevel) { this.privilegeLevel = privilegeLevel; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
再次运行测试类,会发现控制台报错了。
报错的位置加载user注入的时候出现了问题
而且如果拉到最后面,还有更明显的提示Binding validation errors on user- Field error in object 'user' on field 'email': rejected value [springboot#acme-me.cc];
这里已经说了是email这个属性校验失败,拉到最后其实还有很好的中文提示:
这已经告诉了说不是一个合法的邮件地址,说明校验在@ConfigurationProperties下是有效的。
我们更改application.properties文件中的user.email属性
application.properties
其它属性不变,再次运行测试类
会发现绿条一次通过,至于password和privilegeLevel为null,是因为我们配置文件中没有这两个文件,所以这两个文件现在为空。
最后,我们发现两个都能用,那么不得折腾一下吗?如果两个注解都配置了,可以一起用吗?
如果其中某个属性在配置文件中有值,而在属性上使用@Value的字面量去设置值,那么这个属性的值会是配置文件中的还是@Value注入进来的呢?
这里更改一下application.properties文件
server.port=8080 ################User################ user.id=1 user.user-name=admin [email protected] user.password=123
在更改一下User类
package cc.acme_me.springbootannotation.entity; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import org.springframework.validation.annotation.Validated; import javax.validation.constraints.Email; /** * User entity * * @author acme * @ConfigurationProperties 注解用于标识注释参数 prefix标识对应的前缀 * @Component 标识注入Spring容器中(只有注入Spring容器才能使用) */ @ConfigurationProperties(prefix = "user") @Validated @Component public class User { private Integer id; private String userName; @Value("321")//properties文件也配置了这个属性,运行测试类这里会获取哪个值呢? private String password; @Value("#{3*3}") private Integer privilegeLevel; @Email private String email; @Override public String toString() { return "User{" + "id=" + id + ", userName='" + userName + '\'' + ", password='" + password + '\'' + ", privilegeLevel=" + privilegeLevel + ", email='" + email + '\'' + '}'; } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public Integer getPrivilegeLevel() { return privilegeLevel; } public void setPrivilegeLevel(Integer privilegeLevel) { this.privilegeLevel = privilegeLevel; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
上测试结果!
最后的最后,在这里说一下使用原则:在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value;如果专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties;