Springboot基础知识(03)- 配置绑定
配置绑定就是把配置文件中的值与 JavaBean 中对应的属性进行绑定。通常,我们会把一些配置信息(例如,数据库配置)放在配置文件中,然后通过 Java 代码去读取该配置文件,并且把配置文件中指定的配置封装到 JavaBean(实体类)中。
SpringBoot 提供了以下 2 种方式进行配置绑定:
使用 @ConfigurationProperties 注解
使用 @Value 注解
1. @ConfigurationProperties
通过 Spring Boot 提供的 @ConfigurationProperties 注解,可以将全局配置文件中的配置数据绑定到 JavaBean 中。
在 “ Springboot基础知识(01)- Spring Boot 简介、配置 Spring Boot 和 Spring Initializr ” 里 SpringbootBasic 项目基础上,修改如下。
1) 创建 src/main/resources/application.yml 文件(中间目录不存在的,新建目录,下同)
1 person: 2 firstName: Tester 3 age: 20 4 male: false 5 birth: 2000/01/01 6 maps: { key1: value1, key2: value2 } 7 lists: 8 - spring 9 - springboot 10 dog: 11 name: dd 12 age: 5
如果转换成 application.properties,对应的格式如下:
person.firstName=Tester
person.age=20
person.male=false
person.birth=2000/01/01
person.maps.key1=value1
person.maps.key2=value2
person.lists[0]=spring
person.lists[1]=springboot
person.dog.name=dd
person.dog.age=5
2) 创建 src/main/java/com/example/entity/Person.java 文件,并将配置文件中的属性映射到这个实体类上,代码如下。
1 package com.example.entity; 2 3 import java.util.Date; 4 import java.util.List; 5 import java.util.Map; 6 import org.springframework.stereotype.Component; 7 import org.springframework.boot.context.properties.ConfigurationProperties; 8 9 /** 10 * 将配置文件中配置的每一个属性的值,映射到这个组件中 11 * @ConfigurationProperties:告诉 SpringBoot 将本类中的所有属性和配置文件中相关的配置进行绑定; 12 * prefix = "person":配置文件中哪个下面的所有属性进行一一映射 13 */ 14 @Component 15 @ConfigurationProperties(prefix = "person") 16 public class Person { 17 private String firstName; 18 private Integer age; 19 private Boolean male; 20 private Date birth; 21 private Map<String, Object> maps; 22 private List<Object> lists; 23 private Dog dog; 24 public Person() { 25 } 26 public Person(String firstName, Integer age, Boolean male, Date birth, 27 Map<String, Object> maps, List<Object> lists, Dog dog) { 28 this.firstName = firstName; 29 this.age = age; 30 this.male = male; 31 this.birth = birth; 32 this.maps = maps; 33 this.lists = lists; 34 this.dog = dog; 35 } 36 public String getFirstName() { 37 return firstName; 38 } 39 public void setFirstName(String firstName) { 40 this.firstName = firstName; 41 } 42 public Integer getAge() { 43 return age; 44 } 45 public void setAge(Integer age) { 46 this.age = age; 47 } 48 public Boolean getMale() { 49 return male; 50 } 51 public void setMale(Boolean male) { 52 this.male = male; 53 } 54 public Date getBirth() { 55 return birth; 56 } 57 public void setBirth(Date birth) { 58 this.birth = birth; 59 } 60 public Map<String, Object> getMaps() { 61 return maps; 62 } 63 public void setMaps(Map<String, Object> maps) { 64 this.maps = maps; 65 } 66 public List<Object> getLists() { 67 return lists; 68 } 69 public void setLists(List<Object> lists) { 70 this.lists = lists; 71 } 72 public Dog getDog() { 73 return dog; 74 } 75 public void setDog(Dog dog) { 76 this.dog = dog; 77 } 78 @Override 79 public String toString() { 80 return "Person {" + 81 "firstName = '" + firstName + '\'' + 82 ", age = " + age + 83 ", male = " + male + 84 ", birth = " + birth + 85 ", maps = " + maps + 86 ", lists = " + lists + 87 ", dog = " + dog + 88 '}'; 89 } 90 }
注:
只有在容器中的组件,才会拥有 SpringBoot 提供的强大功能。如果我们想要使用 @ConfigurationProperties 注解进行配置绑定,那么首先就要保证该对 JavaBean 对象在 IoC 容器中,所以需要用到 @Component 注解来添加组件到容器中。
JavaBean 上使用了注解 @ConfigurationProperties(prefix = "person") ,它表示将这个 JavaBean 中的所有属性与配置文件中以“person”为前缀的配置进行绑定。
3) 创建 src/main/java/com/example/entity/Dog.java 文件,代码如下。
1 package com.example.entity; 2 3 public class Dog { 4 private String name; 5 private String age; 6 public Dog() { 7 } 8 public Dog(String name, String age) { 9 this.name = name; 10 this.age = age; 11 } 12 public void setName(String name) { 13 this.name = name; 14 } 15 public void setAge(String age) { 16 this.age = age; 17 } 18 public String getName() { 19 return name; 20 } 21 public String getAge() { 22 return age; 23 } 24 25 @Override 26 public String toString() { 27 return "Dog {" + 28 "name = " + name + 29 ", age = " + age + 30 '}'; 31 } 32 }
4) 创建 src/main/java/com/example/ApplicationContextUtils.java 文件
1 package com.example; 2 3 import org.springframework.beans.BeansException; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.ApplicationContextAware; 6 import org.springframework.stereotype.Component; 7 8 /* 9 * 在非 SpringBoot 工厂管理的普通类中,如果要获取工厂管理的对象,不能再使用 @Autowired 等注入的注解, 10 * SpringBoot 提供了一个 “ApplicationContextAware” 接口,实现此接口,即可获取工厂管理的全部内容。 11 */ 12 @Component 13 public class ApplicationContextUtils implements ApplicationContextAware { 14 private static ApplicationContext applicationContext; 15 16 @Override 17 public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { 18 this.applicationContext = applicationContext; 19 } 20 21 // 通过属性名获取对象 22 public static Object getById(String id){ 23 Object bean = applicationContext.getBean(id); 24 return bean; 25 } 26 27 // 通过属性类获取对象 28 public static Object getByClass(Class clazz){ 29 Object bean = applicationContext.getBean(clazz); 30 return bean; 31 } 32 // 通过属性类获取对象 33 public static Object getByNameAndClass(String id,Class clazz){ 34 Object bean = applicationContext.getBean(id,clazz); 35 return bean; 36 } 37 38 }
5) 修改 src/main/java/com/example/App.java 文件
1 package com.example; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 6 import com.example.entity.Person; 7 8 @SpringBootApplication 9 public class App { 10 11 public static void main(String[] args) { 12 SpringApplication.run(App.class, args); 13 14 Person person = (Person) ApplicationContextUtils.getById("person"); 15 System.out.println(person); 16 } 17 18 }
6) 运行
...
Person {name = 'Tester', age = 20, male = false, birth = Sat Jan 01 00:00:00 CST 2000, maps = {key1=value1, key2=value2}, lists = [spring, springboot], dog = Dog {name = dd, age = 5}}
2. @Value
当我们只需要读取配置文件中的某一个配置时,可以通过 @Value 注解获取。
在上文 SpringbootBasic 项目基础上,修改如下。
1) 创建 src/main/java/com/example/entity/Person2.java 文件,代码如下。
1 package com.example.entity; 2 3 import java.util.Date; 4 import java.util.List; 5 import java.util.Map; 6 7 import org.springframework.beans.factory.annotation.Value; 8 import org.springframework.stereotype.Component; 9 10 @Component("person2") 11 public class Person2 { 12 @Value("${person.firstName}") 13 private String firstName; 14 @Value("${person.age}") 15 private Integer age; 16 @Value("${person.male}") 17 private Boolean male; 18 @Value("${person.birth}") 19 private Date birth; 20 private Map<String, Object> maps; 21 private List<Object> lists; 22 private Dog dog; 23 24 public Person2() { 25 } 26 public Person2(String firstName, Integer age, Boolean male, Date birth, 27 Map<String, Object> maps, List<Object> lists, Dog dog) { 28 this.firstName = firstName; 29 this.age = age; 30 this.male = male; 31 this.birth = birth; 32 this.maps = maps; 33 this.lists = lists; 34 this.dog = dog; 35 } 36 37 // getter 和 setter 方法参考上文 Person 类,略 38 39 @Override 40 public String toString() { 41 return "Person2 {" + 42 "firstName = '" + firstName + '\'' + 43 ", age = " + age + 44 ", male = " + male + 45 ", birth = " + birth + 46 ", maps = " + maps + 47 ", lists = " + lists + 48 ", dog = " + dog + 49 '}'; 50 } 51 }
2) 修改 src/main/java/com/example/App.java 文件
1 package com.example; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 6 import com.example.entity.Person; 7 import com.example.entity.Person2; 8 9 @SpringBootApplication 10 public class App { 11 12 public static void main(String[] args) { 13 SpringApplication.run(App.class, args); 14 15 Person person = (Person) ApplicationContextUtils.getById("person"); 16 System.out.println(person); 17 18 Person person2 = (Person2) ApplicationContextUtils.getById("person2"); 19 System.out.println(person2); 20 } 21 22 }
3) 运行
...
Person2 {firstName = Tester, age = 20, male = false, birth = Sat Jan 01 00:00:00 CST 2000, maps = null, lists = null, dog = null}
3. @Value 与 @ConfigurationProperties 对比
@Value 和 @ConfigurationProperties 注解都能读取配置文件中的属性值并绑定到 JavaBean 中,但两者存在以下不同。
1) 使用位置不同
@ConfigurationProperties:标注在 JavaBean 的类名上;
@Value:标注在 JavaBean 的属性上。
2) 功能不同
@ConfigurationProperties:用于批量绑定配置文件中的配置;
@Value:只能一个一个的指定需要绑定的配置。
3) 松散绑定支持不同
@ConfigurationProperties:支持松散绑定(松散语法),例如实体类 Person 中有一个属性为 firstName,那么配置文件中的属性名支持以下写法:
person.firstName
person.first-name
person.first_name
PERSON_FIRST_NAME
@Vaule:不支持松散绑定。
4) SpEL 支持不同
@ConfigurationProperties:不支持 SpEL 表达式;
@Value:支持 SpEL 表达式。
5) 复杂类型封装
@ConfigurationProperties:支持所有类型数据的封装,例如 Map、List、Set、以及对象等;
@Value:只支持基本数据类型的封装,例如字符串、布尔值、整数等类型。
6) 应用场景不同
@Value 和 @ConfigurationProperties 两个注解之间,并没有明显的优劣之分,它们只是适合的应用场景不同而已。
若只是获取配置文件中的某项值,则推荐使用 @Value 注解;
若专门编写了一个 JavaBean 来和配置文件进行映射,则建议使用 @ConfigurationProperties 注解。
在选用时,根据实际应用场景选择合适的注解能达到事半功倍的效果。
4. @PropertySource
如果将所有的配置都集中到 application.properties 或 application.yml 中,那么这个配置文件会十分的臃肿且难以维护,因此我们通常会将与 Spring Boot 无关的配置(例如自定义配置)提取出来,写在一个单独的配置文件中,并在对应的 JavaBean 上使用 @PropertySource 注解指向该配置文件。
@PropertySource 指定加载哪个文件,@ConfigurationProperties 指定加载文件中的哪一类属性。@PropertySource + @ConfigurationProperties 解决 @ConfigurationProperties 只能加载主文件内属性问题。
1) 绑定自定义 *.properties
在上文 SpringbootBasic 项目基础上,修改如下。
(1) 创建 src/main/resources/person3.properties 文件,代码如下。
person3.first-name=Tester3 person3.age=23 person3.birth=2005/05/05 person3.male=false person3.maps.key1=value3 person3.maps.key2=value4 person3.lists=e,f,g person3.dog.name=dd3 person3.dog.age=8
(2) 创建 src/main/java/com/example/entity/Person3.java 文件,代码如下。
1 package com.example.entity; 2 3 import java.util.Date; 4 import java.util.List; 5 import java.util.Map; 6 7 import org.springframework.boot.context.properties.ConfigurationProperties; 8 import org.springframework.context.annotation.PropertySource; 9 import org.springframework.stereotype.Component; 10 11 @Component("person3") 12 @ConfigurationProperties(prefix = "person3") 13 @PropertySource(value = "classpath:person3.properties") 14 public class Person3 { 15 private String firstName; 16 private Integer age; 17 private Boolean male; 18 private Date birth; 19 private Map<String, Object> maps; 20 private List<Object> lists; 21 private Dog dog; 22 public Person3() { 23 } 24 public Person3(String firstName, Integer age, Boolean male, Date birth, 25 Map<String, Object> maps, List<Object> lists, Dog dog) { 26 this.firstName = firstName; 27 this.age = age; 28 this.male = male; 29 this.birth = birth; 30 this.maps = maps; 31 this.lists = lists; 32 this.dog = dog; 33 } 34 35 // getter 和 setter 方法参考上文 Person 类,略 36 37 @Override 38 public String toString() { 39 return "Person3 {" + 40 "firstName = " + firstName + 41 ", age = " + age + 42 ", male = " + male + 43 ", birth = " + birth + 44 ", maps = " + maps + 45 ", lists = " + lists + 46 ", dog = " + dog + 47 '}'; 48 } 49 }
(3) 修改 src/main/java/com/example/App.java 文件
1 package com.example; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 6 import com.example.entity.Person; 7 import com.example.entity.Person2; 8 import com.example.entity.Person3; 9 10 @SpringBootApplication 11 public class App { 12 13 public static void main(String[] args) { 14 SpringApplication.run(App.class, args); 15 16 Person person = (Person) ApplicationContextUtils.getById("person"); 17 System.out.println(person); 18 19 Person person2 = (Person2) ApplicationContextUtils.getById("person2"); 20 System.out.println(person2); 21 22 Person person3 = (Person3) ApplicationContextUtils.getById("person3"); 23 System.out.println(person3); 24 } 25 26 }
(4) 运行
...
Person3 {firstName = Tester3, age = 23, male = false, birth = Thu May 05 00:00:00 CST 2005, maps = {key2=value4, key1=value3}, lists = [e, f, g], dog = Dog {name = dd3, age = 8}}
2) 绑定自定义 *.yml
@PropertySource 默认不支持 yml 文件的解析,需要重写 DefaultPropertySourceFactory 的 createPropertySource 方法。
在上文 SpringbootBasic 项目基础上,修改如下。
(1) 创建 src/main/resources/person4.yml 文件,代码如下。
1 person4: 2 firstName: Tester4 3 age: 26 4 male: true 5 birth: 2008/08/08 6 maps: { key1: value5, key2: value6 } 7 lists: 8 - spring 9 - springmvc 10 - spirngboot 11 dog: 12 name: dd4 13 age: 12
(2) 创建 src/main/com/example/CustomPropertySourceFactory.java 文件,代码如下。
1 package com.example; 2 3 import java.io.IOException; 4 import java.util.List; 5 6 import org.springframework.core.io.support.DefaultPropertySourceFactory; 7 import org.springframework.core.io.support.EncodedResource; 8 import org.springframework.core.env.PropertySource; 9 import org.springframework.boot.env.YamlPropertySourceLoader; 10 11 public class CustomPropertySourceFactory extends DefaultPropertySourceFactory { 12 13 @Override 14 public PropertySource<?> createPropertySource(String name, EncodedResource resource) throws IOException { 15 if (resource == null){ 16 return super.createPropertySource(name, resource); 17 } 18 List<PropertySource<?>> sources = new YamlPropertySourceLoader().load(resource.getResource().getFilename(), resource.getResource()); 19 return sources.get(0); 20 } 21 }
(3) 创建 src/main/java/com/example/entity/Person4.java 文件,代码如下。
1 package com.example.entity; 2 3 import java.util.Date; 4 import java.util.List; 5 import java.util.Map; 6 7 import org.springframework.boot.context.properties.ConfigurationProperties; 8 import org.springframework.context.annotation.PropertySource; 9 import org.springframework.stereotype.Component; 10 11 import com.example.CustomPropertySourceFactory; 12 13 @Component("person4") 14 @ConfigurationProperties(prefix = "person4") 15 @PropertySource(value = "classpath:person4.yml", factory = CustomPropertySourceFactory.class) 16 public class Person4 { 17 private String firstName; 18 private Integer age; 19 private Boolean male; 20 private Date birth; 21 private Map<String, Object> maps; 22 private List<Object> lists; 23 private Dog dog; 24 public Person4() { 25 } 26 public Person4(String firstName, Integer age, Boolean male, Date birth, 27 Map<String, Object> maps, List<Object> lists, Dog dog) { 28 this.firstName = firstName; 29 this.age = age; 30 this.male = male; 31 this.birth = birth; 32 this.maps = maps; 33 this.lists = lists; 34 this.dog = dog; 35 } 36 37 // getter 和 setter 方法参考上文 Person 类,略 38 39 @Override 40 public String toString() { 41 return "Person4 {" + 42 "firstName = " + firstName + 43 ", age = " + age + 44 ", male = " + male + 45 ", birth = " + birth + 46 ", maps = " + maps + 47 ", lists = " + lists + 48 ", dog = " + dog + 49 '}'; 50 } 51 }
(4) 修改 src/main/java/com/example/App.java 文件
1 package com.example; 2 3 import org.springframework.boot.SpringApplication; 4 import org.springframework.boot.autoconfigure.SpringBootApplication; 5 6 import com.example.entity.Person; 7 import com.example.entity.Person2; 8 import com.example.entity.Person3; 9 import com.example.entity.Person4; 10 11 @SpringBootApplication 12 public class App { 13 14 public static void main(String[] args) { 15 SpringApplication.run(App.class, args); 16 17 Person person = (Person) ApplicationContextUtils.getById("person"); 18 System.out.println(person); 19 20 Person person2 = (Person2) ApplicationContextUtils.getById("person2"); 21 System.out.println(person2); 22 23 Person person3 = (Person3) ApplicationContextUtils.getById("person3"); 24 System.out.println(person3); 25 26 Person person4 = (Person4) ApplicationContextUtils.getById("person4"); 27 System.out.println(person4); 28 } 29 30 }
(5) 运行
...
Person4 {firstName = Tester4, age = 26, male = true, birth = Fri Aug 08 00:00:00 CST 2008, maps = {key1=value5, key2=value6}, lists = [spring, springmvc, spirngboot], dog = Dog {name = dd4, age = 12}}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)