@Value和@ConfigurationProperties:
@Value注解与@ConfigurationProperties都是对对象属性进行注入配置的注解。
@Value注解:
//源码:
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
String value();
}
- @Value注解是spring框架的注解,用于对对象属性的注入。
- @Value注解只有一个value属性,值可以是字面量,#{SPEL}表达式,配置文件的${key}值等。
- 能作用在方法(一般是setter方法)、属性、参数、注解上。但是一般会在方法或者属性上使用该注解。
使用方法:
@ToString
@Component
public class Student {
//字面量,作用在成员变量里面
@Value(value = "张三")
private String name;
//SPEL表达式
@Value(value = "#{5+6}")
private int age;
//引用外部配置文件的属性值
@Value("${student.sex}")
private boolean sex;
private String fatherName;
private String motherName;
private String teacherName;
//作用在setter方法上
@Value(value = "李四")
public void setFatherName(String fatherName){
this.fatherName = fatherName;
}
//理论上@Value注解应该使用在setter方法上,例如上面的setFatherName,但是也可以作用在下面方法,把motherName和teacherName属性也复制成value的值
@Value(value = "王五")
public void setMAndT(String motherName,String teacherName){
this.motherName = motherName;
this.teacherName = teacherName;
}
}
配置文件配置:
student:
sex: true
测试类:
@SpringBootTest
class SpringbootstudyApplicationTests {
@Autowired
private Student student;
@Test
void test1() {
System.out.println(student);
}
}
//执行结果:
//Student(name=张三, age=11, sex=true, fatherName=李四, motherName=王五, teacherName=王五)
@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 ignoreUnknownFields() default true;
}
- @ConfigurationProperties注解是spring boot的注解,用于配置文件对对象属性的配置。
- 不支持字面量,也不支持SPEL表达式。
- 从上面源码可知,该注解能作用在类和方法上。
- 有四个属性:
a)prefix:配置文件key的前缀,给属性进行值的注入时会加上此前缀,例如设为teacher,然后属性值为name,name就会把配置文件中的key为teacher.name的值进行注入。
b)value:与prefix一样的作用。与prefix不能同时设置,除非设置的值一样。
c)ignoreInvalidFields:是否忽略无效的字段,默认不忽略。
d)ignoreUnknownFields:是否忽略未知字段,默认忽略。
prefix与value的值不能有大写字母,不能下划线,可以中划线,不然会非法字符报错。
ignoreInvalidFields演示:
@Setter
@ToString
@Component
@ConfigurationProperties(prefix = "pet")
public class Pet {
private String name;
private boolean sex;
}
pet:
name: 旺财
sex: 女
master: 张三
测试代码:
@SpringBootTest
class SpringbootstudyApplicationTests {
@Autowired
private Pet pet;
@Test
void test() {
System.out.println(pet);
}
}
结果:
分析:因为ignoreInvalidFields是是否忽略无效字段,默认false不忽略,所以,Pet类中的sex属性是布尔类型,而配置文件中的该字段是字符串String类型,所以会抛出异常。
也可以设置为true,忽略无效字段:
结果为:
分析:sex字段因为无效被忽略了,使用默认值。
ignoreUnknownFields字段演示:
@Setter
@ToString
@Component
@ConfigurationProperties(prefix = "pet",ignoreUnknownFields = false)
public class Pet {
private String name;
private boolean sex;
}
pet:
name: 旺财
sex: true
master: 张三
测试代码:
@SpringBootTest
class SpringbootstudyApplicationTests {
@Autowired
private Pet pet;
@Test
void test() {
System.out.println(pet);
}
}
结果:
Caused by: org.springframework.boot.context.properties.bind.UnboundConfigurationPropertiesException: The elements [pet.master] were left unbound.
//意思是配置文件中的pet.master在类用没有属性跟他绑定报错
分析:
ignoreUnknownFields的意思是是否忽略未知字段,默认是,所以默认情况下是不会报错,但是我设置为false之后,由于配置文件中有pet.master属性,但是类没有该属性,然后配置为不忽略未知字段,所以报错。
@ConfigurationProperties注解还支持JSR303数据校验:
@Setter
@ToString
@Component
@ConfigurationProperties(prefix = "pet")
@Validated
public class Pet {
@Email //对name进行邮箱校验
private String name;
private boolean sex;
}
pet:
name: 旺财
sex: true
@SpringBootTest
class SpringbootstudyApplicationTests {
@Autowired
private Pet pet;
@Test
void test() {
System.out.println(pet);
}
}
结果:
Field error in object 'pet' on field 'name': rejected value [旺财]; codes [Email.pet.name,Email.name,Email.java.lang.String,Email]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [pet.name,name]; arguments []; default message [name],[Ljavax.validation.constraints.Pattern$Flag;@48bfb884,.*]; default message [不是一个合法的电子邮件地址]; origin class path resource [application.yml]:6:9
//因为pet.name不是邮箱格式,所以数据校验生效报错了。
支持松散绑定:
属性名匹配:
- teacher.schoolName.
- teacher.school_name
- teacher.school-name
- TEACHER.SCHOOLNAME 等等
大小写不敏感,如果大小写不敏感之后有多个相同的属性,则只对第一个进行注入。以上可以互相配置使用。
例子:
@Component
@Data
@ConfigurationProperties(prefix = "person.configuration")
public class Person {
private String firstName;
private String last_name;
private String BORN_LOCATION;
}
PERSON:
configuRation:
first-name: 乔丹
LASTNAME: 迈克尔
born_locAtion: 纽约
测试代码:
@SpringBootTest
class SpringbootstudyApplicationTests {
@Autowired
Person person;
@Test
void test() {
System.out.println(person);
}
}
//结果:
//Person(firstName=乔丹, last_name=迈克尔, BORN_LOCATION=纽约) 都能注入
区别总结:
比较项 | @Value | @ConfigurationProperties |
---|---|---|
使用方式 | 能够批量地注入配置文件中的属性 | 需要一个个指定 |
所属框架 | Spring | Spring Boot |
SPEL | 支持 | 不支持 |
JSR303数据校验 | 不支持 | 支持 |
松散绑定 | 不支持 | 支持 |
复杂类型绑定 | 不支持 | 支持 |
关于@ConfigurationProperties的复杂类型的绑定的例子可以看博主的另一篇文章:
Spring Boot application.yml文件语法
使用场景:
- 如果要对对象尤其是复杂对象进行配置的话推荐使用@ConfigurationProperties。
- 如果要对注入数据进行校验的话推荐使用@ConfigurationProperties。
- 如果我们只是在某个业务逻辑中需要用到配置文件的某一个值,推荐使用@Value。
- 如果需要用到SPEL表达式的话推荐使用@Value。
- 如果是spring的项目那就只能是@Value。