springBoot读取配置文件的注解@ConfigurationProperties及与@Value区别

2021-02-04 10:44:43 浏览数 (1)

文章目录

      • 1.如何使用@ConfigurationProperties
      • 2.配置Annotation Processor
      • 3.通过@Value注解实现
      • 4.@Configuration与@Value对比

在sprigboot中,处理配置文件最好的方法是采用@ConfigurationProperties注解。该注解能方便的将配置文件中的属性配置到具体的对象中。 本文基于的springboot版本如下:

代码语言:javascript复制
plugins {
	id 'org.springframework.boot' version '2.4.2'
	id 'io.spring.dependency-management' version '1.0.11.RELEASE'
	id 'java'
	id 'idea'
}

1.如何使用@ConfigurationProperties

如下,假定我们有一个Person的类,有属性name、age、sex、likes等。我们只需要通过@ConfigurationProperties(prefix = “person”)并指定prefix即可对该对象的属性赋值。

代码语言:javascript复制
package com.dhb.entity;

import lombok.Data;
import lombok.ToString;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.List;

@Data
@ToString
@ConfigurationProperties(prefix = "person")
@Component
public class Person {

	private String name;
	private Integer age;
	private String sex;
	private List<String> likes;
}

yaml的配置如下:

代码语言:javascript复制
person:
  name: 张三
  age: 13
  sex: 男
  likes:
    - bike
    - girl
    - movie

在这个例子中,我们通过@ConfigurationProperties注入了string、Integer、以及list。 测试代码如下:

代码语言:javascript复制
package com.dhb;

import com.dhb.entity.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class MySpringBootApplicationTests {

	@Autowired
	Person person;

	@Test
	void contextLoads() {
		System.out.println(person);
	}

}

可以看到输出:

代码语言:javascript复制
Person(name=张三, age=13, sex=男, likes=[bike, girl, movie])

说明注入属性成功。

2.配置Annotation Processor

在使用了ConfigurationProperties注解之后,需要注意的是,当我们在idea中打开Person类,会出现红色的提示“SpringBoot Configuration Annotation Processor not configured”。

该提示的意思是,没有配置springboot对应的注解处理器(Annotation Processor)。经过查阅相关资料,在gradle中的处理方式如下: 即在build.gradle的dependencies {}中增加如下配置:

代码语言:javascript复制
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'

即可解决该问题。 如果是maven项目,则增加如下配置:

代码语言:javascript复制
<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-configuration-processor</artifactId>
     <optional>true</optional>
</dependency>

在idea中也推荐了一个链接:

代码语言:javascript复制
https://docs.spring.io/spring-boot/docs/2.1.7.RELEASE/reference/html/configuration-metadata.html#configuration-metadata-annotation-processor

在此链接中可以发现,在Gradle 4.5之前的版本配置:

代码语言:javascript复制
dependencies {
	compileOnly "org.springframework.boot:spring-boot-configuration-processor"
}

而在Gradle 4.6及之后的版本:

代码语言:javascript复制
dependencies {
	annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"
}

从compileOnly 变成了annotationProcessor。

3.通过@Value注解实现

如果我们不采用@ConfigurationProperties,那么我们仍然能够通过@Value注解来实现上述功能。但是@value比较复杂,需要在每个属性上面去指定。

代码语言:javascript复制
package com.dhb.entity;

import lombok.Data;
import lombok.ToString;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.List;

@Data
@ToString
@Component
public class Person1 {
	@Value("${person.name}")
	private String name;
	@Value("${person.age}")
	private Integer age;
	@Value("${person.sex}")
	private String sex;
	@Value("${person.likes}")
	private List<String> likes;
}

那么这样也能够将相关的属性注入。 但是需要注意的是,上述写法会报错:

代码语言:javascript复制
package com.dhb;

import com.dhb.entity.Person;
import com.dhb.entity.Person1;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class MySpringBootApplicationTests {

	@Autowired
	Person person;

	@Autowired
	Person1 person1;
	@Test
	void contextLoads() {
		System.out.println(person);
		System.out.println(person1);
	}

}

错误提示:

代码语言:javascript复制
Caused by: java.lang.IllegalArgumentException: Could not resolve placeholder 'person.likes' in value "${person.likes}"

这说明,yaml中的list没办法采用@Value的方式进行注入。如果需要注入,则需要修改:

代码语言:javascript复制
person:
  name: 张三
  age: 13
  sex: 男
  likes: bike,girl,movie

然后调用测试代码:

代码语言:javascript复制
Person(name=张三, age=13, sex=男, likes=[bike, girl, movie])
Person1(name=张三, age=13, sex=男, likes=[bike, girl, movie])

这样采用逗号分隔的方式进行注入在两种配置中都支持。

4.@Configuration与@Value对比

这两个注解的主要区别见下表:

区别项

@ConfigurationProperties

@Value

功能说明

能够批量将配置文件中的属性进行注入

只能按当个属性进行注入

松散绑定(比较松散的语法)

支持

不支持

spring EL

不支持

支持

JSR303数据校验

支持

不支持

复杂类型封装

支持

不支持

上述松散绑定,指的是对于属性的注入不一定要求是equals的属性才能注入,如:

代码语言:javascript复制
person:
  name: 张三
  age: 13
  sex: 男
  likes: bike,girl,movie
  english_name: james

代码:

代码语言:javascript复制
@Data
@ToString
@ConfigurationProperties(prefix = "person")
@Component
public class Person {

	private String name;
	private Integer age;
	private String sex;
	private List<String> likes;
	private String  englishName;
}

上述将english_name注入到englishName是可以成功的:

代码语言:javascript复制
Person(name=张三, age=13, sex=男, likes=[bike, girl, movie], englishName=james)

对于spring 的EL表达式,@Value的配置默认就是EL表达式,采用${}的方式,支持EL表达式提供的所有语法。

对于JSR303数据校验,我们可以引入validation包:

代码语言:javascript复制
	implementation 'org.springframework.boot:spring-boot-starter-validation'

之后,修改Person类:

代码语言:javascript复制
@Data
@ToString
@ConfigurationProperties(prefix = "person")
@Component
@Validated
public class Person {

	@Email
	private String name;
	private Integer age;
	private String sex;
	private List<String> likes;
	private String  englishName;
}

增加@Validated,然后我们将Email添加到name上。 执行测试代码,我们可以看到输出:

代码语言:javascript复制
Binding to target org.springframework.boot.context.properties.bind.BindException: Failed to bind properties under 'person' to com.dhb.entity.Person failed:

    Property: person.name
    Value: 张三
    Origin: class path resource [application.yaml] - 6:9
    Reason: 不是一个合法的电子邮件地址

而相同的方式如果在@Value的注解中去实现的话,不会生效。

0 人点赞