配置文件
SpringBoot使用一个全局的配置文件,配置文件名是固定的(application.properties或application.yml)。
配置文件的作用:修改SpringBoot自动配置的默认值,SpringBoot在底层都给我们自动配置好了。
以前的配置文件;大多都使用的是 xxxx.xml文件。
.yml是YAML语言的文件,以数据为中心,比json、xml等更适合作为配置文件。
配置例子:
YAML:
server: port: 8081
XML:
<server> <port>8081</port> </server>
YAML语法
基本语法
使用缩进表示层级关系
缩进时不允许使用Tab键,只允许使用空格
缩进的空格数目不重要,只要相同层级的元素左侧对齐即可
大小写敏感
application.yml:
server: port: 8081 path: /hello
值的写法
YAML 支持的三种数据结构:
字面量:单个的、不可再分的值
对象:键值对的集合
数组:一组按次序排列的值
字面量:普通的值(数字,字符串,布尔)
k: v:字面直接来写
字符串默认不用加上单引号或者双引号
“”:双引号:不会转义字符串里面的特殊字符
特殊字符会作为本身想表示的意思
name: "zhangsan \n lisi" 输出:zhangsan 换行 lisi
单引号:会转义特殊字符,特殊字符最终只是一个普通的字符串数据
name: 'zhangsan \n lisi' 输出:zhangsan \n lisi
对象、Map(属性和值)(键值对)
k: v 在下一行来写对象的属性和值的关系,注意缩进和空格。
对象还是k: v的方式
friends: lastName: Keafmd age: 20
行内写法:
friends: {lastName: Keafmd,age: 18}
数组(List、Set)
用 - 值表示数组中的一个元素。
pets: ‐ cat ‐ dog ‐ pig
行内写法:
pets: [cat,dog,pig]
配置文件值注入
代码演示
Person:
package com.keafmd.springboot.bean; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; import org.springframework.validation.annotation.Validated; import javax.validation.constraints.Email; import java.util.Date; import java.util.List; import java.util.Map; /** * Keafmd * * @ClassName: Person * @Description: * @author: 牛哄哄的柯南 * @date: 2021-02-23 12:47 */ /** * 将配置文件中配置的每一个属性的值,映射到这个组件中 * @ConfigurationProperties :告诉SpringBoot将本类中的所有属性和配置文件相关的配置进行绑定 * prefix = "person" :配置文件中哪个属性进行一一映射 * * 只有这个组件时容器中的组件吗,才能使用容器提供的功能 */ @Component @ConfigurationProperties(prefix = "person") public class Person { private String lastName; private Integer age; private Boolean boss; private Date birthday; private Map<String,Object> maps; private List<Object> lists; private Dog dog; public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } public Boolean getBoss() { return boss; } public void setBoss(Boolean boss) { this.boss = boss; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public Map<String, Object> getMaps() { return maps; } public void setMaps(Map<String, Object> maps) { this.maps = maps; } public List<Object> getLists() { return lists; } public void setLists(List<Object> lists) { this.lists = lists; } public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } @Override public String toString() { return "Person{" + "lastName='" + lastName + '\'' + ", age=" + age + ", boss=" + boss + ", birthday=" + birthday + ", maps=" + maps + ", lists=" + lists + ", dog=" + dog + '}'; } }
Dog:
package com.keafmd.springboot.bean; /** * Keafmd * * @ClassName: Dog * @Description: * @author: 牛哄哄的柯南 * @date: 2021-02-23 12:50 */ public class Dog { private String name; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "Dog{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
application.yml:
person: lastName: Keafmd age: 18 boss: false birthday: 2020/02/02 maps: {k1: v1,k2: v2} lists: - lisi - zhaoliu - Keafmd - xiaolan dog: name: 二狗 age: 2
测试代码:
package com.keafmd.springboot; import com.keafmd.springboot.bean.Person; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationContext; /** * SpringBoot单元测试 * 可以再测试期间很方便的类似编码一样进行自动注入等容器 */ @SpringBootTest class SpringBoot02ConfigApplicationTests { @Autowired Person person; @Test public void contextLoads() { System.out.println(person); } }
运行结果:
Person{lastName='Keafmd', age=18, boss=false, birthday=Sun Feb 02 00:00:00 CST 2020, maps={k1=v1, k2=v2}, lists=[lisi, zhaoliu, Keafmd, xiaolan], dog=Dog{name='二狗', age=2}}
导入配置文件处理器,使编写配置有提示
注意:我们可以在pom.xml中导入配置文件处理器,以后编写配置就有提示了。
<!--导入配置文件处理器,配置文件进行绑定就会有提示--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> <optional>true</optional> </dependency>
properties配置文件在idea中默认utf-8可能会乱码
把application.yml的person注释掉,在application.properties文件中进行编写。
application.properties:
# 配置person的值 person.last-name=张三 person.age=18 person.boss=false person.birthday=2022/02/02 person.maps.k1=v1 person.maps.k2=v2 person.lists=a,b,c person.dog.name=二狗 person.dog.age=3
我们再次运行测试代码会发现,会出现中文乱码的情况。
解决办法:
设置好再次运行测试代码
运行结果:
Person{lastName='张三', age=18, boss=false, birthday=Sun Feb 02 00:00:00 CST 2020, maps={k1=v1, k2=v2}, lists=[a, b, c], dog=Dog{name='二狗', age=3}}
@Value获取值和@ConfigurationProperties获取值比较
配置文件yml还是properties他们都能获取到值
如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value
如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties
application.properties:
# 配置person的值 person.last-name=张三 person.age=18 person.boss=false person.birthday=2022/02/02 person.maps.k1=v1 person.maps.k2=v2 person.lists=a,b,c person.dog.name=二狗 person.dog.age=3
Person:(部分代码,get和set以及toString不展示了)
package com.keafmd.springboot.bean; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; import org.springframework.validation.annotation.Validated; import javax.validation.constraints.Email; import java.util.Date; import java.util.List; import java.util.Map; /** * Keafmd * * @ClassName: Person * @Description: * @author: 牛哄哄的柯南 * @date: 2021-02-23 12:47 */ /** * 将配置文件中配置的每一个属性的值,映射到这个组件中 * @ConfigurationProperties :告诉SpringBoot将本类中的所有属性和配置文件相关的配置进行绑定 * prefix = "person" :配置文件中哪个属性进行一一映射 * * 只有这个组件时容器中的组件吗,才能使用容器提供的功能 */ @Component //@ConfigurationProperties(prefix = "person") public class Person { /** * <bean class = "Person"> * <property name = "lastName" value = "字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property> * </bean> */ @Value("${person.last-name}") private String lastName; @Value("#{11*2}") private Integer age; @Value("true") private Boolean boss; private Date birthday; private Map<String,Object> maps; private List<Object> lists; private Dog dog; }
运行测试代码的运行结果:
Person{lastName='张三', age=22, boss=true, birthday=null, maps=null, lists=null, dog=null}
属性名匹配规则(Relaxed binding)
– person.firstName:使用标准方式
– person.first-name:大写用-
– person.first_name:大写用_
– PERSON_FIRST_NAME:
• 推荐系统属性使用这种写法
配置文件注入值数据校验
@Value 不支持数据校验。
需要先在pom.xml引入校验的依赖:
<!--引入校验--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId> </dependency>
Person:(部分代码,get和set以及toString不展示了)
package com.keafmd.springboot.bean; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; import org.springframework.validation.annotation.Validated; import javax.validation.constraints.Email; import java.util.Date; import java.util.List; import java.util.Map; /** * Keafmd * * @ClassName: Person * @Description: * @author: 牛哄哄的柯南 * @date: 2021-02-23 12:47 */ /** * 将配置文件中配置的每一个属性的值,映射到这个组件中 * @ConfigurationProperties :告诉SpringBoot将本类中的所有属性和配置文件相关的配置进行绑定 * prefix = "person" :配置文件中哪个属性进行一一映射 * * 只有这个组件时容器中的组件吗,才能使用容器提供的功能 */ @Component @ConfigurationProperties(prefix = "person") @Validated //校验 public class Person { /** * <bean class = "Person"> * <property name = "lastName" value = "字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property> * </bean> */ //@Value("${person.last-name}") //lastName必须是邮箱格式 @Email private String lastName; //@Value("#{11*2}") private Integer age; //@Value("true") private Boolean boss; private Date birthday; private Map<String,Object> maps; private List<Object> lists; private Dog dog; }
运行测试类的结果:
@PropertySource&@ImportResource&@Bean
@PropertySource:加载指定的配置文件
person.properties:
person.last-name=Keafmd-person person.age=18 person.boss=false person.birthday=2022/02/02 person.maps.k1=v1 person.maps.k2=v2 person.lists=a,b,c person.dog.name=二狗 person.dog.age=3
我们想加载这个配置文件的内容,就必须用 @PropertySource指定配置文件
package com.keafmd.springboot.bean; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.PropertySource; import org.springframework.stereotype.Component; import org.springframework.validation.annotation.Validated; import javax.validation.constraints.Email; import java.util.Date; import java.util.List; import java.util.Map; /** * Keafmd * * @ClassName: Person * @Description: * @author: 牛哄哄的柯南 * @date: 2021-02-23 12:47 */ /** * 将配置文件中配置的每一个属性的值,映射到这个组件中 * @ConfigurationProperties :告诉SpringBoot将本类中的所有属性和配置文件相关的配置进行绑定 * prefix = "person" :配置文件中哪个属性进行一一映射 * * 只有这个组件时容器中的组件吗,才能使用容器提供的功能 */ @PropertySource(value = {"classpath:person.properties"}) @Component @ConfigurationProperties(prefix = "person") //@Validated //校验 public class Person { /** * <bean class = "Person"> * <property name = "lastName" value = "字面量/${key}从环境变量、配置文件中获取值/#{SpEL}"></property> * </bean> */ //@Value("${person.last-name}") //lastName必须是邮箱格式 //@Email private String lastName; //@Value("#{11*2}") private Integer age; //@Value("true") private Boolean boss; private Date birthday; private Map<String,Object> maps; private List<Object> lists; private Dog dog; }
运行测试类的测试结果:
Person{lastName='Keafmd-person', age=18, boss=false, birthday=Wed Feb 02 00:00:00 CST 2022, maps={k1=v1, k2=v2}, lists=[a, b, c], dog=Dog{name='二狗', age=3}}
注意:需要把application.properties和application.yml里的person注释掉。
@ImportResource:导入Spring的配置文件,让配置文件里面的内容生效,使用@Bean给容器中添加组件
Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别。
如果想让Spring的配置文件生效,加载进来,需要把@ImportResource标注在一个配置类上。
@ImportResource(locations = {"classpath:beans.xml"}) 导入Spring的配置文件让其生效
创建一个Spring的配置文件beans.xml:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="helloService" class="com.keafmd.springboot.service.HelloService"> </bean> </beans>
创建一个helloService:
package com.keafmd.springboot.service; /** * Keafmd * * @ClassName: HelloService * @Description: * @author: 牛哄哄的柯南 * @date: 2021-02-23 15:59 */ public class HelloService { }
先测试下容器中有没有helloService:
package com.keafmd.springboot; import com.keafmd.springboot.bean.Person; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationContext; /** * SpringBoot单元测试 * 可以再测试期间很方便的类似编码一样进行自动注入等容器 */ @SpringBootTest class SpringBoot02ConfigApplicationTests { @Autowired Person person; @Autowired ApplicationContext ioc; @Test public void testHelloService(){ Boolean b = ioc.containsBean("helloService"); System.out.println(b); } @Test public void contextLoads() { System.out.println(person); } }
运行testHelloService的测试结果:
false
此时说明配置文件并没有生效。
我们把@ImportResource标注在主配置类上。
SpringBoot02ConfigApplication :
package com.keafmd.springboot; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ImportResource; @ImportResource(locations = {"classpath:beans.xml"}) @SpringBootApplication public class SpringBoot02ConfigApplication { public static void main(String[] args) { SpringApplication.run(SpringBoot02ConfigApplication.class, args); } }
再次运行测试方法:
true
但是在实际开发中我们会采用一种更合适的方法,SpringBoot推荐给容器中添加组件的方式是推荐使用全注解的方式。接下来把@ImportResource(locations = {"classpath:beans.xml"})注释掉,创建一个配置类MyAppConfig 。
1、创建配置类,使用 @Configuration ------>Spring配置文件
2、使用 @Bean给容器中添加组件
==MyAppConfig: ==
package com.keafmd.springboot.config; import com.keafmd.springboot.service.HelloService; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; /** * Keafmd * * @ClassName: MyAppConfig * @Description: 配置类 * @author: 牛哄哄的柯南 * @date: 2021-02-23 16:06 */ /** * @Configuration: 指明当前类是配置类,替代之前的Spring配置文件 * 在配置文件中用<bean></bean>标签添加组件 */ @Configuration public class MyAppConfig { //将方法的返回值添加到容器中,容器中这个组件默认的id就是方法名 @Bean public HelloService helloService(){ System.out.println("配置类@Bean给容器添加组件了。。。"); return new HelloService(); } }
再次运行测试方法: