一、配置文件:修改默认配置的核心
Spring Boot 采用 "约定优于配置" 的思想,大部分配置都有默认值。但实际开发中,我们需要根据需求修改默认配置(比如修改端口、配置数据源),这就需要用到配置文件。
1. 配置文件的格式和作用
Spring Boot 有两种全局配置文件,文件名是固定的:
application.properties:键值对格式,入门友好。application.yml:YAML 格式,简洁高效,推荐使用。
作用:修改 Spring Boot 自动配置的默认值(比如端口、数据源、字符编码等)。
两种格式对比(修改端口为 8081)
-
application.properties:server.port=8081
-
application.yml:
java
server:
port: 8081
2. YAML 语法详解(重点)
YAML 是一种以数据为中心的配置语言,比 XML、properties 更简洁,语法规则如下:
(1)基本语法
- 键值对:
k: v(冒号后面必须加空格,否则语法错误)。 - 层级关系:用缩进表示(只能用空格,不能用 Tab,缩进量不限,只要层级一致)。
- 大小写敏感:
port和Port是两个不同的配置项。
java
server:
port: 8081
servlet:
context-path: /demo # 访问根路径为 http://localhost:8081/demo
(2)值的写法
① 字面量(数字、字符串、布尔)
- 字符串默认不用加引号。
- 双引号(""):不转义特殊字符(比如
\n会被解析为换行)。- 示例:
name: "zhangsan\nlisi"→ 输出:zhangsan 换行 lisi。
- 示例:
- 单引号(''):转义特殊字符(比如
\n会被解析为字符串\n)。- 示例:
name: 'zhangsan\nlisi'→ 输出:zhangsan\nlisi。
- 示例:
② 对象 / Map(键值对集合)
两种写法:
-
多行写法(推荐,清晰):
person:
lastName: 张三
age: 18
boss: false -
行内写法:
person: {lastName: 张三, age: 18, boss: false}
③ 数组 / List(有序集合)
两种写法:
-
多行写法(推荐):
pets:
- cat
- dog
- pig -
行内写法:
pets: [cat, dog, pig]
3. 配置文件加载位置(优先级)
Spring Boot 会扫描以下 4 个位置的配置文件,优先级从高到低(高优先级配置会覆盖低优先级,低优先级配置会补充高优先级):
- 项目根目录
/config/下(file:./config/)。 - 项目根目录下(
file:./)。 classpath:/config/下(src/main/resources/config/)。classpath:/下(src/main/resources/)。
实用场景:
- 开发环境:在
src/main/resources/application.yml中配置开发环境(端口 8081)。 - 生产环境:在服务器上 Jar 包同级目录的
config/application.yml中配置生产环境(端口 80),无需修改代码,直接覆盖开发环境配置。
二、高级特性:开发效率翻倍
1. 热部署:修改代码不用重启项目
每次修改代码后,手动重启项目很麻烦。Spring Boot 提供了 spring-boot-devtools 模块,支持热部署(修改代码后自动刷新,无需重启)。
步骤 1:导入依赖
在 pom.xml 中添加:
XML
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<optional>true</optional> <!-- 表示只在开发环境生效 -->
</dependency>
步骤 2:使用热部署
- 修改 Java 代码、配置文件或静态资源后,按
Ctrl + F9(IDEA),项目会自动热部署。 - 注意:热部署仅用于开发环境,生产环境需禁用(避免不必要的性能损耗)。
2. 配置文件值注入:绑定配置到 Java 类
如果配置项很多(比如数据库连接信息、第三方 API 密钥),一个个用 @Value 获取太麻烦。Spring Boot 提供了 @ConfigurationProperties 注解,可将配置文件中的属性批量绑定到 Java 类中。
示例:绑定 person 相关配置
步骤 1:编写 YAML 配置
在 application.yml 中添加:
person:
lastName: 张三
age: 18
boss: false
birth: 2017/12/12
maps: {k1: v1, k2: 123}
lists: [李四, 王五]
dog:
name: 小狗
age: 2
步骤 2:编写 Java 类(Person)
java
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
/**
* @Component:将类交给 Spring 管理(必须是容器中的组件,才能使用 @ConfigurationProperties)
* @ConfigurationProperties(prefix = "person"):绑定配置文件中 prefix 为 person 的属性
*/
@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;
// 必须生成 getter/setter 方法(IDEA 中按 Alt + Insert 快速生成)
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
// 其他 getter/setter 方法省略...
// 内部类 Dog(也可单独创建)
public static class Dog {
private String name;
private Integer age;
// getter/setter 方法省略...
}
}
步骤 3:测试配置注入
在 Controller 中注入 Person 类,访问接口查看结果:
java
@Controller
public class PersonController {
@Autowired // 从 Spring 容器中获取 Person 实例
private Person person;
@ResponseBody
@RequestMapping("/person")
public Person getPerson() {
return person;
}
}
访问 http://localhost:8080/person,会返回配置文件中的数据(JSON 格式),说明配置注入成功。
步骤 4:添加配置提示(可选)
导入配置文件处理器依赖后,编写配置时会有自动提示(避免写错属性名):
XML
<!-- 配置文件处理器,编写配置时会有提示 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
3. @Value 与 @ConfigurationProperties 对比
有时候我们只需要获取单个配置项,可使用 @Value 注解。两者对比:
| 特性 | @ConfigurationProperties | @Value |
|---|---|---|
| 功能 | 批量注入配置文件属性 | 单个注入配置项 |
| 松散绑定 | 支持(如配置文件中 last-name 可绑定 lastName) |
不支持 |
| SpEL 表达式 | 不支持 | 支持(如 @Value("#{11*2}")) |
| JSR303 数据校验 | 支持(如 @Email 校验邮箱格式) |
不支持 |
| 复杂类型封装 | 支持(Map、List、对象) | 不支持 |
使用场景:
- 批量绑定配置项(如 Person 类)→ 用
@ConfigurationProperties。 - 单个配置项(如
server.port)→ 用@Value(示例:@Value("${server.port}") private Integer port;)。
4. 配置文件占位符:动态配置
配置文件支持占位符,可实现动态配置(比如引用其他配置项、生成随机数)。
示例(application.properties):
# 引用前面定义的配置项
person.dog.name=${person.lastName}_dog
# 若 person.hello 未定义,默认值为 "hello"
person.dog.nickname=${person.hello:hello}_nickname
# 生成随机 UUID
person.uuid=${random.uuid}
# 生成随机整数(10-100 之间)
person.score=${random.int[10,100]}
# 生成随机长整数
person.phone=${random.long}
5. 多环境配置(Profile)
实际开发中,开发环境、测试环境、生产环境的配置不同(比如数据库地址、端口)。使用 Profile 可以快速切换环境,无需修改配置文件内容。
方式 1:多配置文件(推荐)
创建多个配置文件,文件名格式为 application-{profile}.properties/yml:
application-dev.yml:开发环境(端口 8081)。application-test.yml:测试环境(端口 8082)。application-prod.yml:生产环境(端口 80)。
在 application.yml 中指定激活的环境:
spring:
profiles:
active: dev # 激活开发环境,可改为 test 或 prod 切换环境
方式 2:YAML 多文档块(单文件)
在一个 application.yml 中用 --- 分隔多个环境,无需创建多个文件:
# 公共配置(所有环境共享)
spring:
profiles:
active: prod # 激活生产环境
---
# 开发环境
server:
port: 8081
spring:
profiles: dev # 标记为开发环境
---
# 测试环境
server:
port: 8082
spring:
profiles: test # 标记为测试环境
---
# 生产环境
server:
port: 80
spring:
profiles: prod # 标记为生产环境
切换环境的其他方式(部署时常用)
-
命令行参数(部署时动态指定):
java -jar spring-boot-demo.jar --spring.profiles.active=prod
-
虚拟机参数(IDEA 中测试):在
Run Configurations->VM options中添加:-Dspring.profiles.active=test。
6. 外部配置加载顺序(部署时重点)
Spring Boot 支持从多个位置加载配置,优先级从高到低(高优先级覆盖低优先级,低优先级补充高优先级)。实际部署时,常用前 3 种方式:
| 优先级 | 配置来源 | 示例 |
|---|---|---|
| 1 | 命令行参数 | java -jar demo.jar --server.port=8088 |
| 2 | 操作系统环境变量 | 系统中配置 SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/prod |
| 3 | Jar 包外部的 application-{profile}.yml |
服务器上 Jar 包同级目录的 config/application-prod.yml |
| 4 | Jar 包内部的 application-{profile}.yml |
项目中 resources/application-prod.yml |
| 5 | Jar 包外部的 application.yml |
服务器上 Jar 包同级目录的 application.yml |
| 6 | Jar 包内部的 application.yml |
项目中 resources/application.yml |
实用场景:项目打包后,无需重新打包,可通过命令行参数或外部配置文件修改配置(比如修改端口、数据库地址)。
示例:部署时修改端口和数据库地址:
java -jar spring-boot-demo.jar \
--server.port=80 \
--spring.datasource.url=jdbc:mysql://192.168.1.100:3306/prod \
--spring.datasource.username=prod_user \
--spring.datasource.password=prod_pwd
三、自动配置原理详解:为什么不用写配置?
这是 Spring Boot 最核心、最难理解的部分。在上篇博客中我们简单提到了自动配置的表层原理,本篇将深入拆解,让你明白 "自动配置" 到底是怎么工作的。
1. 自动配置的核心流程(完整版)
- 启动主程序 :Spring Boot 启动时,加载主配置类(
@SpringBootApplication标注的类)。 - 开启自动配置 :
@SpringBootApplication包含@EnableAutoConfiguration注解,开启自动配置。 - 导入自动配置类 :
@EnableAutoConfiguration触发SpringFactoriesLoader.loadFactoryNames()方法,扫描所有 Jar 包下的META-INF/spring.factories文件,读取EnableAutoConfiguration对应的所有自动配置类(比如HttpEncodingAutoConfiguration、DataSourceAutoConfiguration),并导入 Spring 容器。 - 自动配置类生效 :每个自动配置类会根据 "条件注解" 判断是否生效(比如
@ConditionalOnWebApplication表示仅 Web 应用生效)。 - 配置组件属性 :生效的自动配置类会给 Spring 容器添加核心组件(比如
DispatcherServlet、CharacterEncodingFilter),组件的属性值来自对应的xxxProperties类(比如HttpEncodingProperties),而xxxProperties类的属性与配置文件绑定(比如spring.http.encoding.charset)。 - 用户配置覆盖默认配置 :用户在配置文件中修改的属性(比如
spring.http.encoding.charset=UTF-8)会覆盖xxxProperties类的默认值,从而实现自定义配置。
2. 条件注解:自动配置类的 "开关"
自动配置类之所以能 "按需生效",全靠 @Conditional 及其派生注解。这些注解会判断当前环境是否满足条件,只有满足条件,自动配置类才会生效。
常用派生注解(通俗解释):
| 注解 | 作用 | 示例场景 |
|---|---|---|
| @ConditionalOnWebApplication | 当前是 Web 应用 | 仅 Web 项目加载 Tomcat 配置 |
| @ConditionalOnClass | 项目中存在指定类 | 导入 spring-boot-starter-web 后,才加载 Spring MVC 配置 |
| @ConditionalOnMissingClass | 项目中不存在指定类 | 若未导入 Redis 依赖,不加载 Redis 配置 |
| @ConditionalOnBean | 容器中存在指定 Bean | 只有存在 DataSource Bean,才加载数据库事务配置 |
| @ConditionalOnMissingBean | 容器中不存在指定 Bean | 若用户未自定义 RedisTemplate,则加载默认 RedisTemplate |
| @ConditionalOnProperty | 配置文件中存在指定属性 | 配置 spring.http.encoding.enabled=true 才加载编码配置 |
3. 案例解析:HttpEncodingAutoConfiguration(HTTP 编码自动配置)
以 HttpEncodingAutoConfiguration 为例,看看自动配置类是如何工作的:
java
@Configuration // 标记为配置类
@EnableConfigurationProperties(HttpEncodingProperties.class) // 绑定配置文件属性到 HttpEncodingProperties
@ConditionalOnWebApplication // 仅 Web 应用生效
@ConditionalOnClass(CharacterEncodingFilter.class) // 项目中存在 CharacterEncodingFilter 类才生效
@ConditionalOnProperty(prefix = "spring.http.encoding", value = "enabled", matchIfMissing = true) // 配置文件中 spring.http.encoding.enabled 为 true 或未配置时生效
public class HttpEncodingAutoConfiguration {
// HttpEncodingProperties 已与配置文件绑定,从容器中获取实例
private final HttpEncodingProperties properties;
// 构造器注入 HttpEncodingProperties
public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
this.properties = properties;
}
// 给容器添加 CharacterEncodingFilter 组件(解决乱码)
@Bean
@ConditionalOnMissingBean(CharacterEncodingFilter.class) // 容器中不存在该 Bean 时才添加
public CharacterEncodingFilter characterEncodingFilter() {
CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
filter.setEncoding(this.properties.getCharset().name()); // 从配置文件获取编码格式
filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
return filter;
}
}
对应的 HttpEncodingProperties 类(与配置文件绑定):
java
@ConfigurationProperties(prefix = "spring.http.encoding") // 绑定配置文件中 prefix 为 spring.http.encoding 的属性
public class HttpEncodingProperties {
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); // 默认编码 UTF-8
private Charset charset = DEFAULT_CHARSET;
private Boolean force = true;
// getter/setter 方法省略...
}
总结该案例的工作流程:
- 项目导入
spring-boot-starter-web依赖,存在CharacterEncodingFilter类,且是 Web 应用,所以HttpEncodingAutoConfiguration生效。 HttpEncodingProperties与配置文件的spring.http.encoding前缀绑定,默认编码为 UTF-8。- 自动配置类给容器添加
CharacterEncodingFilter组件,组件的编码格式来自HttpEncodingProperties。 - 用户可在配置文件中修改
spring.http.encoding.charset=GBK,覆盖默认值,实现自定义编码。
4. 如何查看哪些自动配置类生效?
在配置文件中添加 debug=true,启动项目后,控制台会输出 "自动配置报告",清晰显示哪些自动配置类生效、哪些未生效:
debug: true
报告分为两部分:
Positive matches:生效的自动配置类(比如DispatcherServletAutoConfiguration表示 Spring MVC 核心配置生效)。Negative matches:未生效的自动配置类(比如ActiveMQAutoConfiguration因为未导入 ActiveMQ 依赖,所以未生效)。
四、补充知识点:兼容传统 Spring 配置
1. @PropertySource:加载自定义配置文件
默认情况下,@ConfigurationProperties 只会读取 application.properties/yml 全局配置文件。如果想加载自定义配置文件(比如 person.properties),可使用 @PropertySource 注解:
示例:
-
在
src/main/resources下创建person.properties:person.lastName=李四
person.age=20
person.dog.name=旺财 -
在
Person类上添加注解:
java
@Component
@ConfigurationProperties(prefix = "person")
@PropertySource(value = "classpath:person.properties") // 加载自定义配置文件
public class Person {
// 属性、getter/setter 省略...
}
- 注意:
@PropertySource只能加载properties文件,不能加载yml文件。
2. @ImportResource:导入 Spring 传统 XML 配置
Spring Boot 不推荐使用 XML 配置,但如果有遗留的 XML 配置文件(比如 beans.xml),可使用 @ImportResource 注解让其生效:
示例:
- 编写 Spring XML 配置文件
src/main/resources/beans.xml:
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 -->
<bean id="helloService" class="com.example.service.HelloService"/>
</beans>
-
在主配置类上添加注解:
@SpringBootApplication
@ImportResource(locations = "classpath:beans.xml") // 导入 XML 配置文件
public class SpringBootDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootDemoApplication.class, args);
}
} -
推荐方案:Spring Boot 推荐用 全注解方式 替代 XML(
@Configuration + @Bean),示例如下:
java
@Configuration // 替代 XML 配置文件
public class MyConfig {
// @Bean 替代 <bean> 标签,将方法返回值添加到 Spring 容器
@Bean
public HelloService helloService() {
return new HelloService();
}
}
五、常见问题避坑指南
- 配置文件乱码 :IDEA 中进入
File -> Settings -> Editor -> File Encodings,把Default encoding for properties files改成 UTF-8,并勾选Transparent native-to-ascii conversion。 - @ConfigurationProperties 绑定失败 :
- 类必须加
@Component注解(成为 Spring 容器组件)。 - 必须提供 getter/setter 方法。
- 配置文件中属性名与类中属性名一致(支持松散绑定,如
last-name对应lastName)。
- 类必须加
- 热部署不生效 :
- 确认
spring-boot-devtools依赖已添加。 - IDEA 中开启自动编译:
File -> Settings -> Build, Execution, Deployment -> Compiler,勾选Build project automatically。 - 修改代码后按
Ctrl + F9触发热部署。
- 确认
- 静态资源无法访问 :静态资源必须放在
resources/static目录下(比如static/js/jquery.js,访问路径为http://localhost:8080/js/jquery.js)。 - 端口被占用 :修改
server.port为其他端口(比如 8081、8082)。
六、总结
本篇博客深入讲解了 Spring Boot 的核心配置和高级特性,包括配置文件(properties/yml)、热部署、配置注入、多环境配置、自动配置原理等,覆盖了实际开发中的大部分场景。
Spring Boot 的核心思想是 "约定优于配置",通过自动配置和依赖管理,让开发者无需关注框架细节,专注于业务逻辑。掌握了这些知识点,你已经能够独立开发 Spring Boot 项目,并应对各种常见问题。