The difference between SpringBoot | @Value and @ConfigurationProperties

  intellij-idea, java, spring, springboot, value

WeChat Public Number: An Outstanding Disabled Person. If you have any questions, please leave a message backstage. I won’t listen anyway.

Preface

Recently, I had the idea of changing jobs, so I deliberately reviewed the relevant knowledge of SpringBoot and reviewed it in detail. Some of them, I feel, were previously neglected, such as the difference between @Value and @ConfigurationProperties.

How to use

Define two objects, a student object, corresponding to a teacher object, code is as follows:

  • @ConfigurationProperties
  1. Students
@Component
@ConfigurationProperties(prefix = "student") // 指定配置文件中的 student 属性与这个 bean绑定
public class Student {

    private String firstName;

    private String lastName;

    private Integer age;

    private String gender;

    private String city;

    private Teacher teacher;

    private List<String> hobbys;

    private Map<String,Integer> scores;

    //注意,为了测试必须重写 toString 和 get,set 方法
}
  1. Teachers
public class Teacher {

    private String name;

    private Integer age;

    private String gender;

    //注意,为了测试必须重写 toString 和 get,set 方法
}
  1. Test class
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringbootValConproDemoApplicationTests {

    @Autowired
    private Student student;

    @Test
    public void contextLoads() {
        // 这里为了方便,但工作中千万不能用 System.out
        System.out.println(student.toString());
    }
}
  1. Output results
Student{firstName='陈', lastName='一个优秀的废人', age=24, gender='男', city='广州', teacher=Teacher{name='eses', age=24, gender='女'}, hobbys=[篮球, 羽毛球, 兵兵球], scores={java=100, Python=99, C=99}}
  • @Value

@Value supports three ways of taking values, namely literal quantity, ${key} obtaining values from environment variables, configuration files, and #{SpEL}

  1. Students
@Component
//@ConfigurationProperties(prefix = "student") // 指定配置文件中的 student 属性与这个 bean绑定
public class Student {

    /**
     * <bean class="Student">
     *      <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property>
     * <bean/>
     */

    @Value("陈") // 字面量
    private String firstName;

    @Value("${student.lastName}") // 从环境变量、配置文件中获取值
    private String lastName;

    @Value("#{12*2}") // #{SpEL}
    private Integer age;

    private String gender;

    private String city;

    private Teacher teacher;

    private List<String> hobbys;

    private Map<String,Integer> scores;

    //注意,为了测试必须重写 toString 和 get,set 方法
}
  1. test result
Student{firstName='陈', lastName='一个优秀的废人', age=24, gender='null', city='null', teacher=null, hobbys=null, scores=null}

Difference

The difference between the two @ConfigurationProperties @Value
Function Bulk Injection of Attributes in Configuration Files Specify one by one
Loose binding (loose syntax) Support nonsupport
SpEL nonsupport Support
JSR303 data verification Support nonsupport
Complex type package Support nonsupport

As can be seen from the above table, there are mainly 5 differences between @ConfigurationProperties and @Value, of which the first is different in function, which has been demonstrated above. Let me introduce the remaining four differences.

Loose grammar

Loose syntax means that an attribute can have multiple attribute names in the configuration file. For example, chestnut: the firstName attribute in the student class can be called firstName, firstname, firstname, firstname, and firstname in the configuration file. While @ConfigurationProperties supports this naming, @Value does not. Let’s take firstName as an example to test it. The following code:

  • @ConfigurationProperties

The firstName attribute of the student class is defined as first_name in the yml file:

student:
  first_name: 陈  # 学生类的 firstName 属性在 yml 文件中被定义为 first_name
  lastName: 一个优秀的废人
  age: 24
  gender: 男
  city: 广州
  teacher: {name: eses,age: 24,gender: 女}
  hobbys: [篮球,羽毛球,兵兵球]
  scores: {java: 100,Python: 99,C++: 99}

Students:

@Component
@ConfigurationProperties(prefix = "student") // 指定配置文件中的 student 属性与这个 bean绑定
public class Student {

    /**
     * <bean class="Student">
     *      <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property>
     * <bean/>
     */

    //@Value("陈") // 字面量
    private String firstName;

    //@Value("${student.lastName}") // 从环境变量、配置文件中获取值
    private String lastName;

    //@Value("#{12*2}") // #{SpEL}
    private Integer age;

    private String gender;

    private String city;

    private Teacher teacher;

    private List<String> hobbys;

    private Map<String,Integer> scores;

    //注意,为了测试必须重写 toString 和 get,set 方法
}

Test results:

Student{firstName='陈', lastName='一个优秀的废人', age=24, gender='男', city='广州', teacher=Teacher{name='eses', age=24, gender='女'}, hobbys=[篮球, 羽毛球, 兵兵球], scores={java=100, Python=99, C=99}}
  • @Value

Students:

@Component
//@ConfigurationProperties(prefix = "student") // 指定配置文件中的 student 属性与这个 bean绑定
public class Student {

    /**
     * <bean class="Student">
     *      <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property>
     * <bean/>
     */

    //@Value("陈") // 字面量
    @Value("${student.firstName}")
    private String firstName;

    //@Value("${student.lastName}") // 从环境变量、配置文件中获取值
    private String lastName;

    //@Value("#{12*2}") // #{SpEL}
    private Integer age;

    private String gender;

    private String city;

    private Teacher teacher;

    private List<String> hobbys;

    private Map<String,Integer> scores;
    
   //注意,为了测试必须重写 toString 和 get,set 方法
}

Test Result: Startup Report Error, bean Not Found.

From the above two test results, it can be seen that when using @ConfigurationProperties annotation, the attribute name in yml is last_name while the attribute in student class is lastName, but the value can still be obtained, while when using @value, using lastName does report an error. Prove that @ConfigurationProperties supports loose syntax and @value does not.

SpEL

SpEL uses # {…} as delimiter, and all characters in braces will be considered spel, which facilitates dynamic assignment of bean attributes.

  • @Value

As mentioned above, when introducing the usage of @Value annotation, there is such a code:

@Value("#{12*2}") // #{SpEL}
private Integer age;

Prove @Value supports SpEL expressions.

  • @ConfigurationProperties

Since # in yml is treated as a comment, no effect can be seen. So we created a new application.properties file. Commenting on the content of yml file, we write the age attribute in the properties file as follows:

student.age=#{12*2}

Open the @ConfigurationProperties annotation in the student class and annotate the @value annotation. The operation reported an error, and the age attribute matches abnormally.

Note @ConfigurationProperties does not support SpEL

JSR303 data verification

  • @Value

Add @Length check:

@Component
@Validated
//@ConfigurationProperties(prefix = "student") // 指定配置文件中的 student 属性与这个 bean绑定
public class Student {

    /**
     * <bean class="Student">
     *      <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property>
     * <bean/>
     */

    //@Value("陈") // 字面量
    @Value("${student.first-name}")
    @Length(min=5, max=20, message="用户名长度必须在5-20之间")
    private String firstName;

    //@Value("${student.lastName}") // 从环境变量、配置文件中获取值
    private String lastName;

    //@Value("#{12*2}") // #{SpEL}
    private Integer age;

    private String gender;

    private String city;

    private Teacher teacher;

    private List<String> hobbys;

    private Map<String,Integer> scores;
}

yaml:

student:
  first_name: 陈

Test results:

Student{firstName='陈', lastName='null', age=null, gender='null', city='null', teacher=null, hobbys=null, scores=null}

Firstname in yaml is 1 in length. However, the inspection rule stipulates that attributes can still be obtained on 5-20, which means that the inspection is not effective. @Value does not support JSR303 data verification

  • @ConfigurationProperties

Students:

@Component
@Validated
@ConfigurationProperties(prefix = "student") // 指定配置文件中的 student 属性与这个 bean绑定
public class Student {

    /**
     * <bean class="Student">
     *      <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property>
     * <bean/>
     */

    //@Value("陈") // 字面量
    //@Value("${student.first-name}")
    @Length(min=5, max=20, message="用户名长度必须在5-20之间")
    private String firstName;

    //@Value("${student.lastName}") // 从环境变量、配置文件中获取值
    private String lastName;

    //@Value("#{12*2}") // #{SpEL}
    private Integer age;

    private String gender;

    private String city;

    private Teacher teacher;

    private List<String> hobbys;

    private Map<String,Integer> scores;
}

Test Results: Error Reported

[firstName],20,5]; default message [用户名长度必须在5-20之间]

Verification takes effect and supports JSR303 data verification.

Complex type package

Complex type encapsulation refers to that in objects and attributes such as map (such as teacher class and scores map in student class), values cannot be obtained by @Value, for example:

@Component
//@Validated
//@ConfigurationProperties(prefix = "student") // 指定配置文件中的 student 属性与这个 bean绑定
public class Student {

    /**
     * <bean class="Student">
     *      <property name="lastName" value="字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property>
     * <bean/>
     */

    //@Value("陈") // 字面量
    //@Value("${student.first-name}")
    //@Length(min=5, max=20, message="用户名长度必须在5-20之间")
    private String firstName;

    //@Value("${student.lastName}") // 从环境变量、配置文件中获取值
    private String lastName;

    //@Value("#{12*2}") // #{SpEL}
    private Integer age;

    private String gender;

    private String city;

    @Value("${student.teacher}")
    private Teacher teacher;

    private List<String> hobbys;

    @Value("${student.scores}")
    private Map<String,Integer> scores;
}

This is wrong. While introducing the usage of @ConfigurationProperties and @Value above, it has been confirmed that @ConfigurationProperties supports complex type encapsulation. In other words, teacher and scores are directly defined in yaml. @ConfigurationProperties can still get the value.

How to choose?

  • If you just need to get a certain value in the configuration file in a certain business logic, use @ value; For example, suppose the student class now has an additional attribute called school, which is the same for all the students in the school, but it won’t be useful to prevent my system from going to other schools. Then we can give the school attribute directly in yml and get it with @Value . Of course, the above is just a rough example. In actual development, the school attribute should be stored in the database.
  • If a javaBean is specially written to map with the configuration file, we will directly use @ConfigurationProperties.

Complete code

https://github.com/turoDog/Demo/tree/master/springboot_val_conpro_demo

If you think it is helpful to you, please give a Star before you leave. thank you very much.

Postscript

If this article is of any help to you, please help me look good. Your good looks are my motivation to persist in writing.

In addition, after the attention is sent1024Free study materials are available.

For details, please refer to this old article:Python, C++, Java, Linux, Go, Front End, Algorithm Data Sharing

一个优秀的废人,给你讲几斤技术。