目录:
Spring Boot的核心配置与注解 :
作者简介 :一只大皮卡丘,计算机专业学生,正在努力学习、努力敲代码中! 让我们一起继续努力学习!
该文章参考学习教材为:
《Spring Boot企业级开发教程》 黑马程序员 / 编著
文章以课本知识点 + 代码为主线,结合自己看书学习过程中的理解和感悟 ,最终成就了该文章文章用于本人学习使用 , 同时希望能帮助大家。
欢迎大家点赞👍 收藏⭐ 关注💖哦!!!(侵权可联系我,进行删除,如果雷同,纯属巧合)
1. 全局配置文件 ( application.properties / application.yaml:创建项目时候自动生成,其会被“自动导入”到“程序”中 )
- 全局配置文件 ( applicationContext.properties )能够对一些 默认配置值进行修改。Spring Boot 使用一个 ① application.properties 或者 ② application.yaml 的文件作为 全局配置文件,该文件存放 在 src/main/resource目录 或者 类路径的 /config,一般会选择 resource目录。
application.properties配置文件
使用 Spring Initializr方式构建Spring Boot项目时,会在 src/main/resources目录 下 自动生成一个空 application.properties文件 ,Spring Boot项目启动时会自动加载application.properties文件。
我们可以在application.properties 文件中定义 Spring Boot 项目的相关属性,当然,这些相关属性可以是 系统属性、环境变量 、命令参数等信息,也可以是 自定义配置文件名称 和 位置。示例代码如下:
spring.application.name=chapter_02 server.address=80 server.port=8443 spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.config.additional-location= spring.config.location= spring.config.name=application
关于applicationContext.properties 的 案例 ( 例子如 ) :
Pet.java :
package com.myh.chapter_03.domain; public class Pet { private String type; private String name; public String getType() { return type; } public void setType(String type) { this.type = type; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Pet{" + "type='" + type + '\'' + ", name='" + name + '\'' + '}'; } }
Person.java:
package com.myh.chapter_03.domain; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; import java.util.Map; @Component //用于将Person类加入到IOC容器中 (只有这样Person对象才能被 @ConfigurationProperties()注解赋值 ) @ConfigurationProperties(prefix = "person")//将配置文件(application.properties)中以person开头的数据通过“set方法”注入到该类中"属性" public class Person { /** * 通过 @ConfigurationProperties(prefix = "person") 注解来将 application.properties中的"数据"注入到 * 下面的“属性”中 */ private int id; private String name; private List hobby; private String[] family; private Map map; private Pet pet; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List getHobby() { return hobby; } public void setHobby(List hobby) { this.hobby = hobby; } public String[] getFamily() { return family; } public void setFamily(String[] family) { this.family = family; } public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } public Pet getPet() { return pet; } public void setPet(Pet pet) { this.pet = pet; } @Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + '\'' + ", hobby=" + hobby + ", family=" + Arrays.toString(family) + ", map=" + map + ", pet=" + pet + '}'; } }
@ConfigurationProperties(prefix =“person”)注解 的 作用 是将配置文件中以person开头的属性值通过setter方法注入实体类对应属性 中。@Component注解 的作用是将当前注入属性值的 Person类对象作为 Bean 组件放到 Spring 容器中,只有 这样它才能被 @ConfigurationProperties注解赋值。
在上述自定义 Person类中,添加了一个 @Component注解,将该自定义类作为 Spring容器的组件 ( 简而言之,就是 将该类交给IOC容器管理 ),其根本目的是让 Spring Boot 可以自动扫描到该组件,然后进行其他功能实现。
application.properties:
#对实体类对象Person进行属性配置 person.id = 1 person.name = tom person.hobby = play,read,sleep person.family = father,mother person.map.k1 = v1 person.map.k2 = v2 person.pet.type = dog person.pet.name = kity
Spring Boot默认全局配置文件 : application.properties 中的数值将会通过 @ConfigurationProperties( ) 注解 注入到对应 的 实体类 中。
pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.1.3.RELEASE</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com.myh</groupId> <artifactId>chapter_03</artifactId> <version>0.0.1-SNAPSHOT</version> <name>chapter_03</name> <description>Demo project for Spring Boot</description> <properties> <java.version>1.8</java.version> </properties> <dependencies> <!-- web应用场景依赖启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- 单元测试依赖启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>RELEASE</version> <scope>test</scope> </dependency> <!-- “热部署”依赖启动器 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> </dependency> <!-- 是生成配置元数据,以提供更好的配置文件支持和开发体验。它能够帮助开发人员更方便地使用配置文件,并提高开发效率 --> <!-- 在编写application.properties配置文件时,由于要配置的Person 对象属性是我们自定义的,SpringBoot 无法自动识别,所以不会有任何书写提示。在实际开发中,为了出现代码提示的效果来方便配置,在使用@ConfigurationProperties注解进行配置文件属性值注入时,可以在pom.xmI文件中添加一个Spring Boot 提供的配置处理器依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-configuration-processor</artifactId> </dependency> </dependencies> <!-- Maven打包工具插件 --> <!-- <build>--> <!-- <plugins>--> <!-- <plugin>--> <!-- <groupId>org.springframework.boot</groupId>--> <!-- <artifactId>spring-boot-maven-plugin</artifactId>--> <!-- </plugin>--> <!-- </plugins>--> <!-- </build>--> </project>
Chapter03ApplicationTests.java ( 单元测试类 ):
package com.myh.chapter_03; import com.myh.chapter_03.domain.Person; import org.junit.jupiter.api.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) //测试运行器,并加载SpringBoot测试注解 @SpringBootTest //标记该类为“单元测试类”,并加载项目的上下文环境ApplicationContext class Chapter03ApplicationTests { @Autowired private Person person; @Test void contextLoads() { System.out.println(person); } }
运行 contextLoads( )方法,控制台输出结果如下图所示 :
方法执行结果.jpg)信息成功打印,说明了 application.properties文件 属性配置正确,并通过 相关注解自动完成 了 “属性注入”。
application.yaml 配置文件 (推荐使用)
- YAML文件格式 是 Spring Boot 支持 的一种 JSON 超集文件格式,相较于传统的Properties配置文件,YAML文件以数据为核心,是一种更为 直观 且 容易被计算机识别 的 数据序列化格式。
- application.yaml 配置文件的 工作原理 和 application.properties 是一样的,只不过YAML格式配置文件看起来 更简洁一些。
- application.yaml 文件用“ key: + 空格 + value”格式配置属性,使用缩进控制层级关系。这里我们 针对不同数据类型 的 属性值,介绍一下YAML文件配置属性的 写法,具体如下所示 。
当value值为 “普通数据类型” (如 : 数字、字符串、布尔等)
(1) value 值为 普通数据类型( 如数字、字符串、布尔等)
当 YAML 配置文件中配置的 属性值 为 普通数据类型 时,可以 直接配置对应的属性值,同时对 字符串类型的属性值,不需要额外添加引号,示例代码如下 :#当属性值为普通数据类型(如:数字、字符串、布尔等),属性值不需要”额外添加引号“ #8081 和 /hello因为是"普通数据类型",所以都没添加额外的引号 #port和path属于“同一级别” Server: port: 8081 path: /hello
当value值为 “数组” 或 “单列集合”
(2) value 值为 数组 或 单列集合
当YAML 配置文件中配置的 属性值 为 数组 或 单列集合类型 时,主要有 两种书写方式 :①缩进式写法 和 ②行内式写法。①缩进式写法 :
#缩进式写法 person1: hobby: - play - read - sleep person2: hobby: play, read, sleep
②行内式写法 :
#行内式写法 person4: hobby: [play,read,sleep] #使用行内式设置属性值时, []是可以省略的,程序会自动匹配校队"属性的值" person5: hobby: play,read,sleep
当value值为 “Map集合” 或 “对象类型”
(3) value 值为 Map 集合 和 对象类型 时,主要同样 有两种书写方式 :①缩进式写法 和 ②行内式写法。
①缩进式写法 :
#value值为Map或对象时的写法 #Map类型 #缩进式写法 person6: map: k1: v1 k2: v2
②行内式写法 :
#Map类型 #行内式写法,此处用的符号是: 大括号{} person7: map: {k1: v1,k2: k3}
ps :
此处用的 符号 是: 大括号{ }
application.yaml 配置文件的“应用案例”
application.yaml :
#对实体类对象Person进行属性设置, 一样是通过 @ConfigurationProperties()注解来将下面的"数据值"注入到"类"的"属性"中的 person2: id: 1 name: 张三 hobby: [play,read,sleep] family: [father,mother] map: {k1: v1,k2: v2} pet: {type: dog,name: kitty}
Person.java :
package com.myh.chapter_03.domain; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; import java.util.Map; @Component //用于将Person类加入到IOC容器中 (只有这样Person对象才能被 @ConfigurationProperties()注解赋值 ) @ConfigurationProperties(prefix = "person2")//将配置文件( application.yaml )中以person2开头的数据通过“set方法”注入到该类中"属性" public class Person { /** * 通过 @ConfigurationProperties(prefix = "person") 注解来将 application.properties中的"数据"注入到 * 下面的“属性”中 */ private int id; private String name; private List hobby; private String[] family; private Map map; private Pet pet; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List getHobby() { return hobby; } public void setHobby(List hobby) { this.hobby = hobby; } public String[] getFamily() { return family; } public void setFamily(String[] family) { this.family = family; } public Map getMap() { return map; } public void setMap(Map map) { this.map = map; } public Pet getPet() { return pet; } public void setPet(Pet pet) { this.pet = pet; } @Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + '\'' + ", hobby=" + hobby + ", family=" + Arrays.toString(family) + ", map=" + map + ", pet=" + pet + '}'; } }
Chapter03ApplicationTests.java ( 单元测试类 ):
package com.myh.chapter_03; import com.myh.chapter_03.domain.Person; import org.junit.jupiter.api.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) //测试运行器,并加载SpringBoot测试注解 @SpringBootTest //标记该类为“单元测试类”,并加载项目的上下文环境ApplicationContext class Chapter03ApplicationTests { @Autowired private Person person; @Test void contextLoads() { System.out.println(person); } }
运行 contextLoads( )方法,控制台输出结果如下图所示 :
信息成功打印,说明了 application.yaml文件 属性配置正确,并通过 相关注解自动完成了“属性注入”。通过对比可以发现,YAML配置文件的格式更加简洁、方便、推荐使用YAML格式文件。
2. “配置文件属性值” 的 “注入”
使用Spring Boo 全局配置文件 ( application.properties / application.yaml )配置 属性 时,① 如果配置的属性是Spring Boot 默认提供的属性 ,例如服务器端口server.port,那么Spring Boot内部会自动扫描并读取属性值 ( 因为那是 默认提供的属性 )。 ② 如果配置的属性是 用户自定义属性,例如 :自定义的 Person 实体类属性,则必须在程序中注入这些配置属性 ( 通过 @ConfigurationProperties( )注解 来 进行“属性值”的注入 )方可生效。
Spring Boot 支持 多种注入配置文件属性的方式 :
① 使用 注解@ConfigurationProperties ( )注解“注入属性” ② 使用 @Value( )注解 “注入属性”
使用@ConfigurationProperties( )注解将“配置文件”中的“属性值”注入到“属性”中 (注入“个别属性值”)
Spring Boot提供的 @ConfigurationProperties注解 用来快速、方便地 将配置文件中的 自定义
属性值批量注入 某个Bean 对象的 多个对应属性 中。假设现在有一个配置文件,使用 @ConfigurationProperties 注入配置文件的属性,示例代码如下 :@Component //将该类交给IOC容器管理,变成一个bean //该注解的作用: 将配置文件中自定义的"属性值"注入到某个bean对象中的"对应属性"中 @ConfigurationProperties(prefix = "person")//将配置文件( application.properties/application.yaml )中以后person开头的数据通过“set方法”注入到该类中"属性" public class Person { private int id; //属性的set方法 public void setId(int id) { this.id = id; } }
上述代码使用 @Component 和 @ConfigurationProperties(prefix =“person”) 将 配置文件中 的 每个属性映射 到 person类属性中 。
需要注意 的是,使用 @ConfigurationProperties 注解 批量注入属性值 时,要保证配置文件中的 属性 与对应实体类的 属性名一致 ,否则无法 正确 获取并注入属性值 。
使用@Value( )注解将“配置文件”中的“属性值”注入到“属性”中 (注入“个别属性值”)
@Value注解 是 Spring框架提 供的,用来 读取配置文件中的属性值 并逐个 注入Bean对象 的 对应属性中。Spring Boot 框架对Spring 框架中的 @Value注解进行了 默认继承,所以在Spring Boot 框架中还可以使用该注解 读取和注入配置文件属性值。
@Component //将该类交给IOC容器管理,变成一个bean public class Person { @Value("${person.id}") //将配置文件中的“属性值”注入到该类的属性中 private int id; }
上述代码中,@Component注解和 @Value注解用于 注入Person的id属性。其中,@Value 不仅支持注入Person的 id 属性,而且 还可以直接为id属性赋值,这是 @ConfigurationProperties( )注解 不支持 的。
例子如 :
Student.java :
package com.myh.chapter_03.domain; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.List; import java.util.Map; @Component //将该类添加到IOC容器中,作为一个bean(被IOC容器管理) public class Student { //用该注解将配置文件中的"属性值"注入到该类的“属性”中 @Value("${person.id}") private int id; @Value("${person.name}") private String name; private List hobby; private String[] family; private Map map; private Pet pet; @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", hobby=" + hobby + ", family=" + Arrays.toString(family) + ", map=" + map + ", pet=" + pet + '}'; } }
pom.xml :
#对实体类对象Person进行属性设置, 一样是通过 @ConfigurationProperties()注解来将下面的"数据值"注入到"类"的"属性"中的 person: id: 1 name: tom hobby: [play,read,sleep] family: [father,mother] map: {k1: v1,k2: v2} pet: {type: dog,name: kitty}
Chapter03ApplicationTests.java (测试类):
package com.myh.chapter_03; import com.myh.chapter_03.domain.Person; import com.myh.chapter_03.domain.Student; import org.junit.jupiter.api.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) //测试运行器,并加载SpringBoot测试注解 @SpringBootTest //标记该类为“单元测试类”,并加载项目的上下文环境ApplicationContext class Chapter03ApplicationTests { @Autowired private Student student; @Test public void studentTest() { System.out.println(student); } }
运行 studentTest( )方法,控制台输出结果如下图所示 :
注意点 :
使用 @Value( )注解 注入的 属性类型 只能是“ 基本数据类型”。
两种注解“对比分析” :
@ConfigurationProperties( )注解 和 @Value( )注解 的对比 如下表所示 :
对比 @ConfigurationProperties( )注解 @Value( )注解 底层框架 SpringBoot Spring 功能 批量注入配置文件中的属性 单个注入 setter 方法 需要 不需要 复杂类型属性注入 支持 支持 松散绑定 支持 不支持 JSR303 数据校验 支持 不支持 SpEL表达式 不支持 支持
底层框架
@ConfigurationProperties注解是 Spring Boot框架自带 的;而 @Value 注解是 Spring 框架支持的,
只不过Spring Boot框架对Spring 进行了 默认支持,所以也可以使用@Value 注解的相关功能。
功能
@ConfigurationProperties能够将配置文件中的属性 批量注入 Bean对象,而@Value 只能 一个一个单独注入。
属性 setter 方法
- 在使用 @ConfigurationProperties注解进行配置文件 属性值读取注入 时,还必须为 每一个属性 设置 setter方法,通过对应的注解才能够将配置文件中的属性一一匹配并注入对应的 Bean 属性上。如果配置文件中没有配置属性值,则会自动将对应的 Bean 属性设置为空。
(用 @ConfigurationProperties注解必须为每一个属性设setter方法,这样才能完成属性值的注入)- @Value 完全不需要为属性设置setter方法,该注解会先通过表达式读取配置文件中指定的属性值,然后自动注入下方的Bean属性上。如果读取的配置文件属性为空,进行属性注入时程序会自动报错。
复杂类型属性注入
@ConfigurationProperties( )注解 和 @Value注解 支持 任意数据类型 的属性注入,包括基本数据类型和复杂数据类型。
松散绑定
@ConfigurationProperties注解进行配置文件属性值注入时,支持松散绑定语法。例如Person类有一个字符串类型的属性firstName,那么在配置文件中进行属性配置时可以使用如下配置方式,示例代码如下 :
person.firstName = james //标准写法,对应Person类属性名 person.first-name = james //使用横线“-”分隔多个单词 person.first_name = james //使用下划线"_"分隔多个单词 person.FIRST_NAME = james //使用大小写格式,推荐常量属性配置
如果要 注入上述松散绑定语法的属性,那么使用 @Value 注入是无效的,只能使用@ConfigurationProperties。
JSR303 数据校验
@ConfigurationProperties注解进行配置文件属性值注入时,支持JSR303数据校验 ,其主要作用是 校验配置文件 中 注入对应Bean属性 的值是否符合相关值的规则,示例代码如下 :
@Component //加入到IOC容器中 @ConfigurationProperties(prefix = "person") @Validated //引入Spring框架支持的"数据校验规则" public class Example { @Email //对属性进行规则匹配 private String email; public void setEmail(String email) { this.email = email; } }
上述代码中,使用 @ConfigurationProperties注解注入配置文件属性值时,在实体类Example上引入 @Validated 注解进行数据校验,在属性email 上引入@Email 注解进行邮件规则校验。如果注入的配置文件属性值不符合相关校验规则,程序会自动报错。@Value 注解不支持 JSR303数据校验功能。
SpEL表达式 ( 使用“SpEL表达式”为属性“直接注入值” )
@Value 注解 注入配置文件属性时,支持 SpEL表达式语法,即“#{xx}”。例如 Person 类有一个整数类型的属性id,直接使用 SpEL 表达式语法进行属性注入 ( 使用SpEL表达式直接为属性注入值 )
示例代码如下 ://用SpEL来定义一个值, #{5*2} 是一个简单的数学表达式,它计算 5乘以 2的结果,将给结果注入到id属性中 @Value("#{5*2}") private int id;
上述代码在 不使用配置文件 的情况下,直接使用 @Value注解 支持的 SpEL表达式注入Bean ( 通过该 注解支持的SpEL表达式来“直接”为“属性注入值” )。而 @ConfigurationProperties注解 不支持此功能。
如何选择使用这“两种注解”?
- 如果只是针对某一个业务需求,要引入配置文件中的个别属性值,推荐使用 @Value( )注解。
( 如果只要 注入一两个属性值,用 @Value( )注解 )- 如果针对某个JavaBean类,需要 批量注入属性值,则推荐使用@ConfigurationProperties( )注解
注解。
(如果要 注入多个属性值,推荐使用 @ConfigurationProperties( )注解)
3. Spring Boot “自定义配置” (“自定义配置文件”时,需要手动加载该配置文件)
- Spring Boot 免除了项目中大部分的手动配置,对于 一些特定情况,我们可以通过修改全局配置文件以适应具体生产环境,可以说,几乎 所有的配置都可以 写在全局配置文件中,SpringBoot会 自动加载全局配置文件 从而免除我们手动加载的烦恼。
- 但是,如果我们自定义配置文件,Spring Boot 是 无法识别 这些 配置文件 的,此时就需要我们 手动加载。
使用@PropertySource( )注解 “加载Properties配置文件”
如果 要加载自定义配置文件,可以使用 @PropertySource( )注解 和 @ Configuration( )注解 实现。
@PropertySource注解可以指定 自定义配置文件 的 位置和名称。
@Configuration注解可以 将实体类指定为自定义配置类。(系统默认的的配置文件为 : spring.properties ,系统会 自动加载该配置文件 的,但如果是自己创建一个新的配置文件,系统不会进行加载,要手动配置,系统才能进行加载。)
如果需要将自定义配置文件中的属性值注入实体类属性,可以使用 @ConfigurationProperties( ) 注解 或 @Value( ) 注解 注入属性值。
例子如 :
打开项目的 resources目录,在项目的类路径下新建一个 test.properties :
#该配置文件为“自定义的配置文件”,要进行配置后,系统才会加载该“配置文件” #对实体类对象Myproperties进行属性配置 test.id = 1 test.name = test
MyProperties.java :
package com.myh.chapter_03.domain; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.PropertySource; /** * ①"@Configuration"注解用于定义"配置类",注解中包含了一些方法,这些方法会产生Bean,并交由Spring容器管理。 * ( 该注解和 @Component注解功能类似 : 都是将给该类加入到IOC容器中,被IOC容器管理 ) * * ②@Configuration注解标记类为“配置类”,这里等同于“@Component注解” */ @Configuration //标记该类为"配置类",将给类交给IOC容器管理 @PropertySource("classpath:test.properties") //指定"自定义的配置文件"的位置 /** @EnableConfigurationProperties()注解是配合 @ConfigurationProperties()注解一起使用的。如果自定义配置类使用了 @Component()注解而非 @Configuration()注解时,那么@EnableConfigurationProperties()注解可以省略 */ @EnableConfigurationProperties(MyProperties.class) //开启“该配置类”的“属性注入功能” @ConfigurationProperties("test") //指定将“自定义的配置文件”中以test开头的属性值注入到类中属性 public class MyProperties { //自定义的"配置类",用于借助相关注解来引入“自定义配置文件”并注入“属性值” private int id; private String name; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "MyProperties{" + "id=" + id + ", name='" + name + '\'' + '}'; } }
在上述文件中,MyProperties 是一个 自定义配置类,用于借助相关注解引入 自定义配置文件并注入自定义属性值。上面的类中用到的注解的介绍具体如下 :
注解 描述 @Configuration( )注解 @Configuration注解用于表示当前类是一个自定义配置类,该类会作为Bean 组件添加到Spring 容器中,这里等 同于@Component 注解。 @PropertySource( )注解 @PropertySource(“classpath:test.properties”)注解指定了自定义配置文件的 位置和名称。
此示例表示自定义配置文件为classpath类路径下的test.properties 文件。@ConfigurationProperties( )注解 @ConfigurationProperties(prefix = “test”) 注解将上述 自定义配置文件 test.properties 中以test 开头的属性值注入该配置类属性中。 @EnableConfigurationProperties
(MyProperties.class)该注解表示开启对应配置类MyProperties的属性注入功能,该注解是配合 @ConfigurationProperties 使用的。如果自定义配置类使用了 @Component 注解而非@Configuration注解,那么 @EnableConfigurationProperties注解可以省略。 Chapter03ApplicationTests3.java : (测试类) :
package com.myh.chapter_03; import com.myh.chapter_03.domain.MyProperties; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest //标记该类为“单元测试类”,并加载项目的上下文环境ApplicationContext public class Chapter03ApplicationTests3 {
@Autowired private MyProperties myProperties; @Test public void myPropertiesTest() { System.out.println(myProperties); } }
执行 myPropertiesTest( )方法,查看控制台输出效果 :
使用@lmportResource( )注解 “加载XML配置文件”
传统的 Spring 项目 配置主要 基于XML文件。Spring Boot框架在 Spring4.x基础上进行了改进,默认不再使用 XML文件配置项目,且XML配置文件不会加载到Spring容器中。如果希望将外部的XML文件加载到程序中,可以使用 @lmportResource( )注解 加载配置文件。
@lmportResource( )注解 标注在一个 配置类 上,通常放置在应用启动类上,使用时需要 指定 XML 配置文件的路径和名称。
例子如 :
打开项目的 resources目录,新建一个 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标签来将MyService标记为Spring容器中的组件(即将MyService加入到IOC容器中,被其管理) --> <bean id="myService" class="com.myh.chapter_03.config.MyService"/> </beans>
beans.xml配置文件 是使用传统的Spring框架 XML方式编写的配置文件,在该配置文件中通过 <bean>标签将MyService 标注为Spring容器中的 Bean 组件 ( 将该类加入到IOC容器中,被IOC容器管理 )。
Chapter03Application.java ( 主程序启动类 ) :
package com.myh.chapter_03; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.ImportResource; @SpringBootApplication //标记该类为"主程序启动类" //加载“自定义配置的.xml文件”的位置 @ImportResource("classpath:beans.xml") public class Chapter03Application { public static void main(String[] args) { SpringApplication.run(Chapter03Application.class, args); } }
(3编写完 Spring 的XML配置文件后,SpringBoot默认是无法识别的,为了保证XML配置文件生效,需要在 项目启动类上 添加 @lmportResource( )注解 来指定XML 文件位置,让该配置文件生效。
Chapter03ApplicationTests3.java ( 单元测试类 ):
package com.myh.chapter_03; import com.myh.chapter_03.domain.MyProperties; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationContext; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest //标记该类为“单元测试类”,并加载项目的上下文环境ApplicationContext public class Chapter03ApplicationTests3 { @Autowired private ApplicationContext applicationContext; @Test public void iocTest() { System.out.println(applicationContext.containsBean("myService")); } }
执行 iocTest( )方法,查看控制台输出效果 :
从上图可以看出,测试方法iocTest( )运行成功,输出结果true 表示 Spring 容器中已经包含了 id 为 myService实例,说明 @lmportResource注解成功加载了 Spring 框架的XML配置文件。
使用@Configuration( )注解编写自定义配置类
Spring Boot中引入 自定义的XML配置文件,这种配置方式在实际开发中的特殊情况下才会使用。在Spring Boot开发中,“约定大于配置”的思想,更推荐使用配置类的方式代替 XML 配置。使用 @Configuration( )注解 (该注解可配合 @Bean( ) 注解使用 )可以 指定配置类,它的作用和XML配置是一样的。
配置类 中 @Bean( )注解 方法 返回的“对象” 都将 作为Bean注入Spring容器,并且默认情况下,使用 @Bean( )注解的方法名 就是 组件名。
(@Bean( )注解将方法“返回的对象”交给 IOC容器管理,默认情况下,方法名就是“组件名”)
例子如 :
MyService.java :
package com.myh.chapter_03.config; public class MyService { }
MyConfig.java :
package com.myh.chapter_03.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration //标记该类为“配置类”,同时将该类交给IOC容器管理 public class MyConfig { @Bean //该注解的作用: ①将方法的返回对象交给IOC容器管理 ②默认情况下,方法名就是“组件名” public MyService myService() { return new MyService(); } }
MyConfig是 @Configuration( )注解 声明的配置类( 类似于声明了一个XML配置文件),该配置类会 被Spring Boot 自动扫描识别;使用 @Bean 注解的myService( )方法,其返回值对象 会作为组件添加到Spring 容器中( 类似于XML配置文件中的<bean>标签配置 ),并且该组件的id 默认是方法名 : myService。
Chapter03ApplicationTests4.java :
package com.myh.chapter_03; import com.myh.chapter_03.domain.MyProperties; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.context.ApplicationContext; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest //标记该类为“单元测试类”,并加载项目的上下文环境ApplicationContext public class Chapter03ApplicationTests4 { @Autowired private ApplicationContext applicationContext; @Test public void iocTest() { System.out.println(applicationContext.containsBean("myService")); } }
执行 iocTest( )方法,查看控制台输出效果 :
从上图可以看出,测试方法iocTest( )运行成功,显示运行结果为true,表示 Spring 容器中已经包含了id为myService的实例对象组件,说明使用 自定义配置类 ( 用 @Configuration注解 进行 配置 )的方式同样可以向Spring容器添加和配置组件。
4. Profile”多环境配置“ (满足“多种环境”的需求)
- 在实际开发中,应用程序 通常 需要部署到不同的运行环境 中,如 开发环境、测试环境、生产环境等。不同的环境可能需要不同的环境配置,针对这种情况,显然手动修改配置文件适应不同开发环境的做法是不太现实的,此时通常会对项目进行多环境配置。
- SpringBoot框架提供了两种多环境配置的方式,分别是 :
① “Profile文件” 多环境配置 和 ② “@Profile注解” 多环境配置。
使用“Profile文件”进行“多环境配置” ( resources目录下创建“Profile文件” + “全局配置文件”中激活“指定环境”的“配置文件”)
- 使用 “Profile文件” 进行 多环境配置 在Spring Boot 框架中,使用Profile配置文件进行多环境配置时,该 配置文件名必须满足 : application-{profile}.properties 的格式,其中 {profile) 对应 具体的环境标识。这里以开发环境、测试环境和生产环境为例,编写对应环境的 配置文件,示例代码如下 :
( resources目录下创建这些“配置文件”)
application-dev.properties //开发环境配置文件 application-test.properties //测试环境配置文件 application-prod.properties //生产环境配置文件
- 如果 想要使用上述对应环境的配置文件,只需要在SpringBoot全局配置文件中 激活 “指定环境”的 配置文件即可。例如,在① 控制台 执行下列命令 激活环境配置 :
java -jar xxx.jar --spring.profiles.active=dev
除了在 控制台使用命令激活指定环境的方式外,还可以在 ② 项目全局配置文件中配置springprofiles.active 属性激活配置。这里以激活 dev开发环境配置文件 为例,在全局配置文件application.properties 中 配置激活环境 的 属性,示例代码如下 :
# 激发开发环境的配置文件 (通过该配置激活“指定环境”的“配置文件”) spring.profiles.active=dev
例子如 :
第一步、
打开resources目录,在该目录下按照Profile文件命名规则创建不同运行环境对应的配置文件,这里分别创建 application-dev.properties、application-test.properties 和 application-prod.properties 多环境配置文件,并在各个配置文件中对服务端口进行不同的设置 :
application-dev.properties :sever.port=8081
application-test.properties :
sever.port=8082
application-prod.properties :
sever.port=8083
在Spring Boot项目中,程序内部默认端口为 8080 ,而上述示例中通过 Profile文件进行了多环境配置,不同的运行环境设置了不同的服务端口号。其中,application-dev.properties开发环境中,设置服务端口号为:8081 application-test.properties测试环境中,设置服务端口号为 :8082; application-prod.properties生产环境中,设置服务端口号为8083。
第二步、
打开的resources目录下的全局配置文件 application.properties,在该配置文件中配置 spring.profiles.active属性 选择性 激活Profile文件 设置,示例代码如下 :application.properties :
#指定要激活的“指定环境”的“配置文件” spring.profiles.active=dev
第三步、
运行 “主程序启动类” ,控制台输出内容如下 :
从上图可以看出,程序正常启动,并 显示服务启动的端口号为8081,这与 选择激活的配置文件application-dev.properties端口号一致,说明 Profile多环境配置文件生效。如果想使用 Profile 文件 激活其他环境,可以在全局配置文件 application.properties中设置对应的配置文件,重启项目查看效果。
使用“@Profile注解”进行“多环境配置” (创建类,在类下使用@Profile( )注解来标记该类作为一个“Profile文件” + “全局配置文件”中激活“指定环境”的“配置文件”)
除了使用 Profile文件进行多环境配置外,还可以使用 @Profile注解进行多环境配置。
@Profile( )注解主要作用于“类”,主要操作有 :
① 通过 value属性 指定 配置环境( 等同于 Profile文件名称中的profile 值 )。 ② 使用 @Profile注解配置的环境,同样需要在 全局配置文件中激活。例子如 :
DBController.java (接口):
package com.myh.chapter_03.config.controller; import com.myh.chapter_03.config.DBConnector; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class DBController { @Autowired private DBConnector dbConnector; @GetMapping("/showDB") public void showDB() { dbConnector.configure(); } }
DBController接口的“三个实现类” :
DevDBConnector.java (实现类):
package com.myh.chapter_03.config.Impl; import com.myh.chapter_03.config.DBConnector; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; @Configuration @Profile("dev") //指定多环境配置类标识 (开发环境),通过在全局配置文件中指定dev来使用该环境配置 public class DevDBConnector implements DBConnector { @Override public void configure() { System.out.println("数据库配置环境dev"); } }
ProdDBConnector.java (实现类):
package com.myh.chapter_03.config.Impl; import com.myh.chapter_03.config.DBConnector; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; @Configuration @Profile("dev") //指定多环境配置类标识 (开发环境),通过在全局配置文件中指定dev来使用该环境配置 public class DevDBConnector implements DBConnector { @Override public void configure() { System.out.println("数据库配置环境dev"); } }
TestDBConnector.java (实现类):
package com.myh.chapter_03.config.Impl; import com.myh.chapter_03.config.DBConnector; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Profile; /** * @author 莫月辉 * @desctiption * @since 2024/3/27 23:24 */ @Configuration @Profile("test") //指定多环境配置类标识 (测试环境) public class TestDBConnector implements DBConnector { @Override public void configure() { System.out.println("数据库配置环境test"); } }
上述三个实现类都使用了 @Configuration注解 和 @Profile注解,其中,@Configuration注解将实
现类 声明为配置类,可以保证Spring Boot 自动扫描并识别 ( 将给类交给IOC容器管理 );@Profile注解用于进行 多环境配置,并 通过属性 标识 配置环境。
application.properties :
#指定要激活的“指定环境”的“配置文件” spring.profiles.active=dev
在全局配置文件 application.properties 中设置 spring.profiles.active属性激活使用 @Profile注解构建的多环境配置。
DBController.java :
package com.myh.chapter_03.config.controller; import com.myh.chapter_03.config.DBConnector; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class DBController { @Autowired private DBConnector dbConnector; @GetMapping("/showDB") public void showDB() { dbConnector.configure(); } }
@Autowired注解用于注入DBConnector,@GetMapping(“/showDB”)注解用于映射 GET 请求,这里用来映射路径为“/showDB”的请求。
运行“主程序启动类”,控制台输出效果 为 :
从上图可以看出,程序能够正常启动,并且控制台显示dev开发环境的端口号是8081,说明通过 “Profile文件配置的多环境” 仍然在生效 。
接着,在 浏览器上访问“http://localhost:8081/showDB”,查看控制台输出效果,结果如下图所示 :
从上面运行结果可以看出,控制台的端口号为8081,并打印出 指定标识为dev的 数据库配置信息,也就是说 程序执行了数据库连接配置方法configure( )。由此可知无论使 用Profile 文件 还是 @Profile 注解 类都 可以进行多环境配置,而且 相互之间不会干扰。
5. “随机值设置”以及“参数间引用”
- 在 SpringBoot配置文件中 设置属性 时,除了可以像前面示例中显示的 配置属性值外,还可以使用随机值 和 参数间引用对 “属性值”进行设置。
随机值设置
在SpringBoot配置文件中 ,随机值设置使用到了Spring Boot 内嵌的 RandomValuePropertySource类,对一些 隐秘属性值 或者 测试用例属性值进行随机值注入。
随机值设置的 “语法格式”为${random.xx}, xx表示需要指定生成的随机数类型和范围,它可
以生成随机的整数、通用唯一识别码(UUID) 或 字符串,示例代码如下 :#对属性值进行“随机值注入” my.string = ${random.value} //配置随机字符串 my.number = ${random.int} //配置随机整数 my.bignumber = ${random.long} //配置随机long类型数 my.uuid = ${random.uuid} //配置随机UUID类型数 my.number.than.ten = ${random.int(10)} //配置小于10的随机整数 my.number.in.range = ${random.int[1024,65536]} //配置范围在[1024,65536]之间的随机整数
上述代码中,使用 RandomValuePropertySource类中random提供的随机数类型,分别展示了 不同类型随机值 的设置示例。
参数间引用
在SpringBoot配置文件中,配置文件的属性值还可以进行参数间的引用,也就是说,先前定义的属性 可以被引用,并且配置文件可以解析引用的属性值。使用参数间引用的 好处就是,在多个具有相互关联的配置属性中,只需要对其中一处属性预先配置,其他地方都可以引用,省去了后续多处修改的麻烦。
参数间引用的语法格式为${xx},xx 表示先前在 配置文件中已经配置过的属性名,示例代码 :
app.name = MyApp add.description = ${app.name}
在上述 参数间引用设置示例中,先设置了“app.name=MyApp”,将app.name属性的属性值设置为了 MyApp;接着,在app.description属性配置中,使用 ${app.name}对前一个属性值进行了引用。
例子如:
application.properties :
#随机值设置以及参数间引入配置 tom.age = ${random.int[10,20]} tom.description = Tom的年龄可能是${tom.age}
在上述 application.properties配置文件中,先 使用随机值设置了tom.age属性的属性值,该属性值设置在了[10,20]之间,随后使用参数间引用配置了tom.description 属性。
Chapter03ApplicationTests5.java ( 单元测试类 ) :
package com.myh.chapter_03; import com.myh.chapter_03.domain.MyProperties; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; @RunWith(SpringRunner.class) @SpringBootTest //标记该类为“单元测试类”,并加载项目的上下文环境ApplicationContext public class Chapter03ApplicationTests5 { //使用@Value注解 + 参数间引用 来该属性注入“属性值” @Value("${tom.description}") private String description; @Test public void placeholderTest() { //运行该方法 System.out.println(description); } }
需要说明的是,由于 属性description 引用了属性 age 的值,age 是[10,20]范围的随机值,因此执行placeholderTest( )方法输出的结果将是 [10,20]范围的某个值。