Spring Boot中使用YAML配置文件

1. YAML 文件结构和语法

缩进与层次

YAML使用缩进来表示层级关系。每个层级的元素必须比它的父级多一个空格或Tab(推荐使用空格)。例如:

javascript 复制代码
server:
  port: 8080
  address: localhost
列表与映射

列表用 - 开头,映射则用 key: value 形式。可以混合使用。

javascript 复制代码
myapp:
  features:
    - featureA
    - featureB
  settings:
    timeout: 30s
    maxConnections: 50
多行字符串

对于较长的字符串,可以使用 |> 来表示多行文本。|会保留换行符,而>会将多行合并为一行并去掉多余的空白。

javascript 复制代码
message: |
  这是一个多行字符串。
  它保留了换行符。
message2: >
  这也是一个多行字符串。
  但它的换行符被忽略了。
使用锚点和别名避免重复

为了减少冗余,YAML允许使用锚点(&)和别名(*)来引用之前定义的内容。

javascript 复制代码
defaults: &defaults
  timeout: 30s
  retries: 3

service1:
  <<: *defaults
  url: http://service1.example.com

service2:
  <<: *defaults
  url: http://service2.example.com

这里,<<: *defaults 表示将 defaults 中的所有属性合并到当前节点中。

2. 多环境配置

激活特定配置文件

你可以通过命令行参数、系统属性或在代码中设置激活的配置文件。

  • 命令行:java -jar app.jar --spring.profiles.active=dev
  • 系统属性:-Dspring.profiles.active=dev
  • 应用程序内:spring.profiles.active=dev
组合配置文件

如果你有多个配置文件,比如 application.ymlapplication-dev.yml,后者会覆盖前者中的相同配置项。

3. 属性占位符和默认值

占位符引用

可以使用 ${} 语法来引用其他属性或环境变量,并可设置默认值。

javascript 复制代码
database:
  url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/dbname
动态表达式

除了静态替换外,还可以使用 Spring Expression Language (SpEL) 来动态计算值。

javascript 复制代码
maxThreads: '#{T(java.lang.Runtime).getRuntime().availableProcessors() * 2}'

4. 配置类与 @ConfigurationProperties

自定义配置类

创建一个POJO类用于接收配置项,并使用 @ConfigurationProperties 注解绑定到这个类。

java 复制代码
@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
    private String name;
    private List<String> admins = new ArrayList<>();
    
    // getters and setters
}
验证配置

为了确保配置的有效性,可以在配置类上添加JSR-303/Bean Validation注解。

java 复制代码
@ConfigurationProperties(prefix = "myapp")
public class MyAppProperties {
    @NotNull
    private String name;
    
    @Size(min = 1)
    private List<String> admins = new ArrayList<>();

    // getters and setters
}

5. 使用 @Value 注解注入配置

简单注入

直接使用 @Value 注入简单的配置项。

java 复制代码
@Component
public class MyComponent {
    private final String apiKey;

    public MyComponent(@Value("${myapp.api-key}") String apiKey) {
        this.apiKey = apiKey;
    }
}
结合 SpEL 使用

@Value 支持 SpEL 表达式,允许进行更复杂的逻辑操作。

java 复制代码
@Value("#{${myapp.timeout} * 1000}")
private int timeoutInMillis;

SpEL不仅限于简单的数学运算,还可以执行条件判断、调用方法等复杂操作。例如:

java 复制代码
@Value("#{T(java.lang.Math).random() > 0.5 ? 'high' : 'low'}")
private String randomLevel;
引用其他bean的方法

你可以在表达式中直接引用其他bean的方法:

java 复制代码
@Component
public class UtilityService {
    public String generateToken() {
        return UUID.randomUUID().toString();
    }
}

@Component
public class MyComponent {
    @Value("#{@utilityService.generateToken()}")
    private String token;
}

6. 加密敏感信息

Jasypt

Jasypt 是一个流行的库,用于加密 Spring Boot 应用程序中的敏感数据。你可以在 pom.xml 中添加依赖,并使用它来加密配置项。

XML 复制代码
<dependency>
    <groupId>com.github.ulisesbocchio</groupId>
    <artifactId>jasypt-spring-boot-starter</artifactId>
    <version>3.0.3</version>
</dependency>

然后,在配置文件中使用 {cipher} 标签来标记加密过的值。

javascript 复制代码
myapp:
  secret: ENC(encrypted_value)

要解密这些值,你需要设置 jasypt.encryptor.password 属性来指定加密密码。

javascript 复制代码
jasypt:
  encryptor:
    password: my_secret_password

除了前面提到的基本用法,Jasypt还支持多种加密算法以及密钥管理策略。你可以通过配置 jasypt.encryptor.* 属性来自定义加密行为。

javascript 复制代码
jasypt:
  encryptor:
    algorithm: PBEWithMD5AndDES
    password: my_secret_password
    iv-generator-classname: org.jasypt.iv.NoIvGenerator

此外,Jasypt也提供了对非对称加密的支持,如RSA。

7. 使用外部化配置

优先级顺序

Spring Boot 按照一定的顺序加载配置源,从命令行参数到默认配置文件。了解这些来源的加载顺序有助于正确地管理和覆盖配置。

  1. 命令行参数
  2. 来自 SPRING_APPLICATION_JSON 的属性(嵌入在环境变量或系统属性中)
  3. 操作系统的环境变量
  4. Java 系统属性 (System.getProperties())
  5. RandomValuePropertySource 配置的随机属性 (random.*)
  6. 打包在 jar 包外的应用配置文件 (application-{profile}.properties.yml)
  7. 打包在 jar 包内的应用配置文件 (application-{profile}.properties.yml)
  8. 配置文件(如 bootstrap.propertiesbootstrap.yml),适用于微服务架构中的配置服务器
  9. 默认属性(通过 SpringApplication.setDefaultProperties 指定)

8. 高级特性

条件化配置

使用 @ConditionalOnProperty 注解可以根据配置属性的存在与否来有条件地加载bean。

java 复制代码
@Bean
@ConditionalOnProperty(name = "myapp.enabled", havingValue = "true")
public MyService myService() {
    return new MyServiceImpl();
}

除了 @ConditionalOnProperty,还有其他条件注解,如 @ConditionalOnClass, @ConditionalOnMissingBean 等,可以根据类路径上的类、是否存在某些bean等条件来决定是否加载配置。

java 复制代码
@Bean
@ConditionalOnClass(name = "com.example.MyLibraryClass")
public MyService myService() {
    return new MyServiceImpl();
}
使用 EnvironmentPostProcessor 扩展配置处理

为了在应用程序启动前修改环境变量,你可以实现 EnvironmentPostProcessor 接口。例如,根据系统属性动态调整配置文件的位置:

java 复制代码
public class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor {
    @Override
    public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application) {
        String customConfigLocation = System.getProperty("custom.config.location");
        if (customConfigLocation != null) {
            environment.getPropertySources().addFirst(new ResourcePropertySource(customConfigLocation));
        }
    }
}

然后注册这个处理器:

javascript 复制代码
spring.application.additional-spring-configuration-metadata=classpath:META-INF/spring-configuration-metadata.json

并且在 META-INF/spring.factories 中声明:

javascript 复制代码
org.springframework.boot.env.EnvironmentPostProcessor=com.example.CustomEnvironmentPostProcessor
配置元数据支持

为了提高开发体验,Spring Boot 提供了对配置元数据的支持,使得IDE能够更好地理解你的配置选项,并提供自动完成等功能。这需要在项目中包含 spring-boot-configuration-processor 依赖。

XML 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>
相关推荐
野犬寒鸦2 分钟前
力扣hot100:相交链表与反转链表详细思路讲解(160,206)
java·数据结构·后端·算法·leetcode
ytadpole1 小时前
揭秘设计模式:工厂模式的五级进化之路
java·设计模式
计算机毕业设计木哥1 小时前
计算机毕设选题:基于Python+Django的B站数据分析系统的设计与实现【源码+文档+调试】
java·开发语言·后端·python·spark·django·课程设计
失散131 小时前
分布式专题——1.2 Redis7核心数据结构
java·数据结构·redis·分布式·架构
用户3721574261351 小时前
Python 实现 HTML 转 Word 和 PDF
java
a587691 小时前
Java核心概念精讲:TCP与UDP的区别、Java NIO的几个核心组件与HTTP和HTTPS的区别等(46-50)
java·面试·nio
渣哥2 小时前
ConcurrentHashMap 的 get 要不要加锁?一次“多此一举”的心路历程
java
愿你天黑有灯下雨有伞2 小时前
一种基于注解与AOP的Spring Boot接口限流防刷方案
java·spring boot·后端
MuMuMu#2 小时前
JAVA NIO学习笔记基础强化学习总结
java·学习·nio
拾忆,想起2 小时前
Redis复制延迟全解析:从毫秒到秒级的优化实战指南
java·开发语言·数据库·redis·后端·缓存·性能优化