一、配置文件
1.SpringBoot使用一个全局的配置文件,配置文件名是固定的,SpringBoot有有以下两种方式的配置文件:
- application.properties
– 自动生成的文件
修改http服务端口的命令为(SpringBoot默认为8080):
- application.yml
– 需要手动创建
修改http服务端口的命令为(与application.properties格式不一样):
2.配置文件的作用:修改SpringBoot自动配置的默认值。
配置文件放在src/main/resources目录或者类路径/config下
.yml是YAML(YAML Ain’t Markup Language)语言的文件,以数据为中心,比json、xml等更加适合做配置文件。
二、YAML语法
1.基本语法
k:(空格)v:表示一对键值对(空格必须有)
以空格的缩进来控制层级关系,左对齐的一列数据为同一层级
server:
port:8090
path:/hello
2.值的写法
1、字面量:普通的值(数字、字符创、布尔)
k: v
字符串默认不用加上单引号或者双引号
“”:双引号,不会转义字符串中的特殊字符(如\n)
‘’:单引号,会转义特殊字符
2、对象、Map(属性和值或者说键值对)
k: v
在下一行来写对象的属性和值的关系,注意缩进缩进
例如
friends:
name: jack
age: 23
也可以采用行内写法
friends: {name: jack,age: 23}
3、数组(List、Set)
用(短横线)-值表示数组中的一个元素
language:
- Java
- Pathon
- C++
行内写法
language: [Java,Pathon,C++]
三、yaml配置文件值获取
@ConfigurationProperties: 告诉SpringBoot将本类中所有属性和配置文件中相关的配置进行绑定
通过实验来学习如何从yaml配置文件中获取值,首先是application.yaml中的数据:
1、编写代码
server:
port:8081
person:
lastname: zhangsan
age: 22
boss: false
birth: 2020/05/13
maps: {k1: v1,k2: 12}
lists: {lisi,zhaoliu}
dog:
name: 小狗
age: 2
在main/java/包下建立两个类
Person.java代码
package com.yjx.springboot01helloworldquick.bean;
import com.sun.org.apache.xpath.internal.operations.Bool;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.Map;
import java.util.List;
/**
* 将配置文件中配置的每一个属性的值,映射到这个组件中
* @ConfigurationProperties: 告诉SpringBoot将本类中所有属性和配置文件中相关的配置进行绑定
* prefix = "person" : 配置文件中哪个与下面的所有属性进行一一映射
*
* 只有这个组件是容器中的组件,才能使用容器提供的@ConfigurationProperties功能
*/
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String lastname;
private Integer age;
private Boolean boss;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
@Override
public String toString() {
return "Person{" +
"lastname='" + lastname + '\'' +
", age=" + age +
", boss=" + boss +
", birth=" + birth +
", maps=" + maps +
", lists=" + lists +
", 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 getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
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;
}
}
set、get、toString等方法可以通过idea自动实现
alt+insert 打开如下界面
Dog.java
package com.yjx.springboot01helloworldquick.bean;
public class Dog {
private String name;
private Integer age;
public Integer getAge() {
return age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
2、测试
打开test/java下的文件
添加测试语句
package com.yjx.springboot01helloworldquick;
import com.yjx.springboot01helloworldquick.bean.Person;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
/**
* SpringBoot单元测试
*/
@SpringBootTest
class Springboot01HelloworldQuickApplicationTests {
//@Autowired 注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。
@Autowired
Person person;
@Test
void contextLoads() {
System.out.println(person);
}
}
点击contextLoads方法左侧的三角形按钮开始测试
结果显示已从yml配置文件中读取出值。
3、总结
1、@ConfigurationProperties: 告诉SpringBoot将本类中所有属性和配置文件中相关的配置进行绑定,实现从yaml配置文件中获取值;
2、必须是容器中的组件,才能使用容器提供的@ConfigurationProperties功能,所以需要加上@Component注解。
四、properties配置文件编码问题
注释掉yml配置文件中的内容
在application.properties文件中写入配置(与application.yml的配置效果一样)
server.port=8081
# 配置person的值
person.lastname=张三
person.age=23
person.birth=2017/02/12
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=dog
person.dog.age=3
运行发现中文乱码了
解决方案:将编码改成utf-8
在idea的file->settings->Editor->File Encodding中,配置文件默认是utf-8编码的,需要勾选在运行时将utf-8转换成ASCII格式,再次运行程序即可。
五、@ConfigurationProperties和@Value的区别
1、区别
@ConfigurationProperties | @Value | |
---|---|---|
功能 | 批量注入配置文件中的属性 | 一个个指定 |
松散语法绑定(Relaxed binding) | 支持 | 不支持 |
Spring表达式语言(SpEL) | 不支持 | 支持 |
JSR303数据校验 | 支持 | 不支持 |
复杂类型封装 | 支持(可以去除map、list中的数据) | 不支持(仅支持基本类型数据) |
如果说,我们只是在业务逻辑中需要获取一下配置文件中的某项值,使用@Value;
如果,编写了一个javaBean来和配置文件的值进行映射,直接使用@Configuration
属性名匹配规则(Relaxed binding)
- person.firstName : 标准方式
- person.first-name : 大写用-,等同于person.firstName
- person.first_name : 大写用_,等同于person.firstName
- PERSON_FIRST_NAME : 大写+下划线分隔,推荐用于环境变量或命令行参数
2、@Value使用样例
@RestController
public class sayController {
@Value("${person.lastname}") //获取配置文件中的值
private String name;
@Value("#{11*2}") //SpEL运算
private Integer age;
@Value("true") //直接设定值
private boolean boss;
@RequestMapping("/sayInfo")
public String sayInfo(){
return "name:"+name + ", age:"+age+",boss:"+boss;
}
}
运行结果:
六、@PropertySource、@Bean
1、@PropertySource
作用: 加载指定的配置文件。
@ConfigurationProperties(prefix = “person”)默认是从全局配置文件中获取值。
测试:
在resources文件夹下新建一个person.properties配置文件,用来存储person的数据(把原来全局配置文件的person数据剪切过来)。
@PropertySource(value = {"classpath:person.properties"})
@Component
@ConfigurationProperties(prefix = "person")
public class Person {
private String lastname;
private Integer age;
private Boolean boss;
private Date birth;
private Map<String,Object> maps;
private List<Object> lists;
private Dog dog;
2、@Bean
作用:通过配置类给容器添加组件。
测试:
在包下新建service文件夹,文件夹下新建HelloService类;
在包下新建config文件夹,文件下下新建MyConfig类;
//MyConfig.java
import com.yjx.springboot01helloworldquick.service.HelloService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Configuration :指明当前类是一个配置类
*/
@Configuration
public class MyConfig {
//将方法的返回值添加到容器中,容器中这个组件默认id就是方法名
@Bean
public HelloService helloService(){
System.out.println("配置类@Bean给容器中添加组件成功");
return new HelloService();
}
}
在测试文件的类中添加测试代码
@Autowired
ApplicationContext ioc;//ApplicationContext有两种,需导入正确
@Test
public void testHelloService(){
boolean b = ioc.containsBean("helloService");//测试是否存在该组件
System.out.println(b);
}
测试结果
七、配置文件占位符
1、随机数
${random.value}、${random.int}、${random.long}、
${random.int(10)}、${randon.int[1024,65526]}
2、占位符获取之前配置的值,如果没有可以用:指定默认值
# 配置person的值
person.lastname=张三${random.uuid}}
person.age=23
person.birth=2017/02/12
person.boss=false
person.maps.k1=v1
person.maps.k2=14
person.lists=a,b,c
person.dog.name=${person.lastname}_${person.have:big}_dog
person.dog.age=3
八、Profile
Profile是Spring对不同环境提供不同配置功能的支持,可以通过激活、指定参数等方式快速切换环境
1、 多profile文件形式:
- 格式:application-{profile}.properties
–例如:application-dev.properties、 application-prod.properties
新建一个application-dev.properties文件,写入以下数据:
server.port=8082
在默认配置文件application.properties里添加spring.profiles.active=dev
server.port=8081
spring.profiles.active=dev
运行程序,可以发现使用的端口号为8082
2、yml支持多文档块模式
server:
port: 8081
spring:
profiles:
active: prod #激活prod环境
--- #三条短横线用来分离文档块
server:
port: 8083
spring:
profiles: dev
---
server:
port: 8084
spring:
profiles: prod
运行程序,可以发现用的是prod环境的端口号8084
3、激活方式:
- 命令行 --spring.profiles.active=dev
–项目打包为jar包后运行:
java -jar 项目包名.jar --spring.profiles.active=XXX
也可以在测试时,配置传入命令行参数
- 在配置文件中指定 spring.profiles.active=dev
- jvm参数 -Dspring.profiles.active=dev
九、配置文件加载位置
springboot启动会扫描一下位置的application.properties或者application.yml文件作为SpringBoot的默认配置文件
- file:./config/ ——当前项目根目录下的config文件里
- file:./ —— 当前项目的根目录下
- classpath:/config/ ——resource/config
- classpath:/ ——默认的情况,类路径(resources)下
以上是按照优先级从高到低的顺序,所有位置的文件都会被加载,高优先级配置内容会覆盖低优先级配置内容。
可以通过配置spring.config.location来改变默认配置文件位置,项目打包好后,可以使用命令行参数的形式,启动项目的时候来指定配置文件的新位置,这里指定的新的配置文件与项目中的配置文件共同起作用。
十、外部配置的加载顺序
SpringBoot除了可以从项目中的application.properties/application.yml主配置文件中加载配置,还可以从以下位置加载配置:
1、命令行参数:所有的配置都可以在命令行参数中指定,每个配置项前使用–,多个配置间使用空格隔开,例如:
java -jar XXX.jar --server.port=8088 --server.context-path=boot
2、来自java:comp/env的JNDI属性
3、java的系统属性(System.getProperties(""))
4、操作系统环境变量
5、RandomValuePropertySource配置的random.*属性值
6、jar包外部的application-{profile}.properties或application-{profile}.yml(带spring.profile配置)
7、jar包内部的application-{profile}.properties或application-{profile}.yml(带spring.profile配置)
8、jar包外部的application.properties或application.yml(不带spring.profile配置)
9、jar包内部的application.properties或application.yml(不带spring.profile配置)
10、@Configuration注解类上的@PropertySource
11、通过SpringApplication.setDefaultProperties()指定的默认属性
十一、自动配置原理
- SpringBoot启动时加载组配置类,开启自动配置功能@EnableAutoConfiguration
- @EnableAutoConfiguration的作用是:利用EnableAutoConfigurationImportSelector给容器中导入一些组件
精髓:
- SpringBoot启动会加载大量的自动配置类
- 看需要的功能有没有SpringBoot默认写好的自动配置类
- 看这个自动配置类中配置了哪些组件(要用的组件有的话,就不用再配置了)
- 给容易中自动配置类添加组件时,会从properties类中获取某些属性,可以在配置文件中指定这些属性的值。
十二、@Condition & 自动配置报告
@ConditionalOnBean(仅仅在当前上下文中存在某个对象时,才会实例化一个Bean)
@ConditionalOnClass(某个class位于类路径上,才会实例化一个Bean)
@ConditionalOnExpression(当表达式为true的时候,才会实例化一个Bean)
@ConditionalOnMissingBean(仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean)
@ConditionalOnMissingClass(某个class类路径上不存在的时候,才会实例化一个Bean)
@ConditionalOnNotWebApplication(不是web应用,才会实例化一个Bean)
@ConditionalOnBean:当容器中有指定Bean的条件下进行实例化。
@ConditionalOnMissingBean:当容器里没有指定Bean的条件下进行实例化。
@ConditionalOnClass:当classpath类路径下有指定类的条件下进行实例化。
@ConditionalOnMissingClass:当类路径下没有指定类的条件下进行实例化。
@ConditionalOnWebApplication:当项目是一个Web项目时进行实例化。
@ConditionalOnNotWebApplication:当项目不是一个Web项目时进行实例化。
@ConditionalOnProperty:当指定的属性有指定的值时进行实例化。
@ConditionalOnExpression:基于SpEL表达式的条件判断。
@ConditionalOnJava:当JVM版本为指定的版本范围时触发实例化。
@ConditionalOnResource:当类路径下有指定的资源时触发实例化。
@ConditionalOnJndi:在JNDI存在的条件下触发实例化。
@ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者有多个但是指定了首选的Bean时触发实例化。
通过启用debug=true(写在配置文件里),来让控制台打印自动配置报告,可以很方便知道哪些自动配置类生效了。