代码示例:SpringBoot-Labs-Junw jLab-1

1. 概述

Spring Boot 支持 PropertiesYAMLJSON 三种格式的配置文件。目前主流的采用的是 Properties 或是 YAML 格式。本文的示例,我们会以 application.yml 配置文件为主。

主要内容如下:

  1. 自定义配置:读取配置文件中的自定义属性

    • @ConfigurationProperties

    • @Value

  2. 配置引用:配置项可以引用其他的配置项

  3. 命令行配置:用命令行中的配置覆盖掉配置文件中对应属性的值

  4. 多环境配置:多套配置 local、dev、pre、prod 可切换

  5. 自定义配置文件:读取多个配置文件

    • @PropertySources

  6. 配置加载顺序:加载优先级

代码样例:SpringBoot-Labs-Junw - jLab-1

省略了较少使用的配置项随机数、配置加密,后续如果用到的话再进行补充。

2. 自定义配置

  1. application.yml 配置文件中自定义配置

  2. 使用 @ConfigurationProperties@Value 注解,读取该自定义配置

  3. 项目代码使用 Spring io 脚手架初始化生成,所以会与下文略有不同。

2.1 pom 中引入依赖

<?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>3.3.0</version>
        <relativePath/>
    </parent>

    <artifactId>jLab-1-demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    
    <dependencies>
        <!-- Spring Boot Starter 基础依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>

        <!-- Spring Boot 配置处理器 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

</project>

2.1.1 spring-boot-configuration-processor

编译项目时,会扫描 @ConfigurationProperties 注解,生成 spring-configuration-metadata.json 配置元数据文件给 IDEA。这样在 IDEA 中,可以带来两个好处:

  • application.yml 配置文件,添加配置项时,IDEA 会给出提示。

  • 点击配置项时,可以跳转到对应的 @ConfigurationProperties 注解的配置类。

.yml 可以, .yaml 不可以

2.2 配置文件

application.yml 中,添加自定义配置

单词之间,Spring Boot 推荐使用 - 中划线间隔。

work:
  good-job-times: 100 # 特别优秀的完成工作的次数,单位:次。
  completed-job-times: 100 # 完成工作的次数,单位:次

2.3 配置类

创建 WorkProperties 配置类,读取 work 配置项:

  • 在类上,添加 @Component 注解,保证该配置类可以作为一个 Bean 被扫描到。

  • 在类上,添加 @ConfigurationProperties 注解,并设置 prefix = "work" 属性,这样它就可以读取前缀work 配置项,设置到配置类对应的属性上。

@Component
@ConfigurationProperties(prefix = "work")
public class WorkProperties {

    /**
     * 特别优秀的完成工作的次数,单位:次。
     */
    private Integer goodJobTimes;

    /**
     * 完成工作的次数,单位:次。
     */
    private Integer completedJobTimes;

    // ... 省略 set/get 方法
    // 快捷键 Alt + Ins

}

因为 WorkProperties 配置类上的 @ConfigurationProperties 注解,所以我们在编译一次该项目后,可以自动通过 spring-boot-configuration-processor 依赖生成对应的 spring-configuration-metadata.json 配置元数据,路径:target/classes/META-INF/

2.3.1 @ConfigurationProperties 也支持添加在方法上

@Configuration
public class DataSourceConfig {

    @Bean(name = "ordersDataSource")
    @ConfigurationProperties(prefix = "spring.datasource.orders") // 读取 spring.datasource.orders 配置到 HikariDataSource 对象
    public DataSource ordersDataSource() {
        return DruidDataSourceBuilder.create().build();
    }
    
}

2.4 启动类

  • 在 WorkPropertiesCommandLineRunner 类中,我们测试了使用 @ConfigurationProperties 注解的 WorkProperties 配置类,读取 work 配置项的效果。

  • 在 ValueCommandLineRunner 类中,我们测试了使用 @Value 注解,读取 work 配置项的效果。

  • 其中,@Value 注解是 Spring 所提供,@ConfigurationProperties 注解是 Spring Boot 所提供。

代码如下:

@SpringBootApplication
public class JLab1Application {

    public static void main(String[] args) {
        // SpringApplication.run 会调用所有实现了 ApplicationRunner、CommandLineRunner 的类的run方法
        SpringApplication.run(JLab1Application.class, args);
    }

    @Component
    @Order(2) // 排序:加载顺序
    public class WorkPropertiesCommandLineRunner implements CommandLineRunner {
        private final Logger logger = LoggerFactory.getLogger(getClass());

        @Autowired
        private WorkProperties workProperties;

        @Override
        public void run(String... args) {
            logger.info("goodJobTimes:" + workProperties.getGoodJobTimes());
            logger.info("completedJobTimes:" + workProperties.getCompletedJobTimes());
        }

    }

    @Component
    @Order(1)
    public class ValueCommandLineRunner implements CommandLineRunner {
        private final Logger logger = LoggerFactory.getLogger(getClass());

        @Value("${work.good-job-times}")
        private Integer goodJobTimes;

        @Value("${work.completed-job-times}")
        private Integer completedJobTimes;

        @Override
        public void run(String... args) {
            logger.info("goodJobTimes:" + goodJobTimes);
            logger.info("completedJobTimes:" + completedJobTimes);
        }
    }
}

2.4.1 启动应用

执行 JLab1Application 的 #main(String[] args) 方法,启动 Spring Boot 应用启动日志如下,加载顺序与上述代码中 @Order(1) 注解中的设置一致

# ValueCommandLineRunner 日志
2024-06-05T09:34:42.163+08:00  INFO 27384 --- [           main] .JLab1Application$ValueCommandLineRunner : goodJobTimes:100
2024-06-05T09:34:42.163+08:00  INFO 27384 --- [           main] .JLab1Application$ValueCommandLineRunner : completedJobTimes:100

# WorkPropertiesCommandLineRunner 日志
2024-06-05T09:34:42.163+08:00  INFO 27384 --- [           main] lication$WorkPropertiesCommandLineRunner : goodJobTimes:100
2024-06-05T09:34:42.163+08:00  INFO 27384 --- [           main] lication$WorkPropertiesCommandLineRunner : completedJobTimes:100

3. 配置引用

在配置文件中,一个配置项可以引用另外的配置项,进行拼接。

如下所示:

work:
  good-job-times: 100 # 特别优秀的完成工作的次数,单位:次。
  completed-job-times: 100 # 完成工作的次数,单位:次。
  desc: "特别优秀的完成工作 ${work.good-job-times} 次,完成工作 ${work.completed-job-times} 次"

4. 命令行配置

Spring Boot 支持从命令行参数,读取作为配置。

例如,修改服务端口,则会使用 java -jar xxx.jar --server.port=18080 命令,将端口修改为 18080。

通过命令行连续的两个中划线 --,后面接 配置项=配置值 的方式,修改配置文件中对应的配置项为对应的配置值

例如--配置项=配置值。如果希望修改多个配置项,则使用多组 -- 即可。例如说,--配置项1=配置值1 --配置项2=配置值2

命令行的配置高于配置文件

5. 多环境配置

在 Spring Boot 的项目开发中,我们会涉及多个不同的环境,部署 Spring Boot 到对应环境时,需要采用不同的配置

如果只使用一份配置文件,每次部署到不同的环境,就需要重复去修改,显然非常麻烦且容易出错。所以针对多环境场景下,我们会给每个环境创建一个配置文件 application-${profile}.yaml。其中,${profile}环境名,对应到 Spring Boot 项目生效的 Profile

例如application-dev.yaml 配置文件,对应 dev 开发环境。这样,我们在生产环境的服务器上,使用 java -jar xxx.jar --spring.profiles.active=prod 命令,就可以加载 application-prod.yaml 配置文件,从而连接上配置文件配置的生产环境的 MySQL、Redis 等等服务。

5.1 生成脚手架

项目代码使用 Spring io 脚手架初始化生成

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>3.3.0</version>
		<relativePath/>
	</parent>

	<artifactId>jLab-1-demo-profiles</artifactId>

	<dependencies>
 		<!-- 实现对 SpringMVC 的自动化配置 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
	</dependencies>

</project>

5.2 配置文件

resources 目录下,创建 4 个配置文件,对应不同的环境。如下:

  • application.yml ,放不同环境的相同配置。

# 多配置文件中的相同配置项
spring:
  application:
    name:jLab-1-demo-profiles

# application-${profile} 配置文件的优先级更高,会覆盖它
server:
  port: 7080
  • application-local.yml,本地环境。

server:
  port: 8080
  • application-dev.yml,开发环境。

server:
  port: 8081
  • application-prod.yml,生产环境。

server:
  port: 8082

5.3 测试

  • 直接运行,日志如下:

2024-06-05T13:57:04.067+08:00  INFO 34144 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 7080 (http)
  • 修改 application.yml ,指定 dev 作为运行环境

# 多配置文件中的相同配置项
spring:
  application:
    name:jLab-1-demo-profiles
  # 指定配置文件
  profiles:
    active: dev

# application-${profile} 配置文件的优先级更高,会覆盖它
server:
  port: 7080

日志如下:

2024-06-05T13:59:37.037+08:00  INFO 23692 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8081 (http)
  • 修改 IDEA 覆盖配置属性 ,指定运行环境为 prod,旧版本添加 --spring.profiles.active=prod

日志如下:

2024-06-05T14:06:17.024+08:00  INFO 32556 --- [           main] m.j.j.JLab1DemoProfilesApplication       : The following 1 profile is active: "prod"
2024-06-05T14:06:17.547+08:00  INFO 32556 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat initialized with port 8082 (http)

6. 自定义配置文件

原文中此处的样例在 SpringBoot 3.3.0 版本中未复用成功,此处提供另外一种方式

6.1 生成脚手架

修改 pom 文件,如下:

<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>3.3.0</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>jLab-1-demo-configname</artifactId>

    <dependencies>
        <!-- Spring Boot Starter 基础依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
    </dependencies>

</project>

6.2 配置文件

resources 目录下,创建两个配置文件。如下:

  • application.yml 配置内容如下:

	application-test: hahaha
  • rpc.yml 配置内容如下:

	rpc-test: yeah

6.3 启动类

此处使用 @PropertySources 加载多个配置文件,在 ValueCommandLineRunner 中,打印了两个配置文件的配置项。

/**
 * 读取指定配置文件 @PropertySource / 多个配置文件  @PropertySources
 * 可以与下列两个注解搭配使用
 *      - @ConfigurationProperties(prefix = "work")
 *      - @Value("${work.good-job-times}")
 */
@SpringBootApplication
@PropertySources({ @PropertySource("classpath:application.yml"),
        @PropertySource("classpath:rpc.yml") })
public class JLab1DemoConfignameApplication {

    public static void main(String[] args) {
        // 启动 Spring Boot 应用
        SpringApplication.run(JLab1DemoConfignameApplication.class, args);
    }

    @Component
    public class ValueCommandLineRunner implements CommandLineRunner {

        private final Logger logger = LoggerFactory.getLogger(getClass());

        @Value("${application-test}")
        private String applicationTest;

        @Value("${rpc-test}")
        private String rpcTest;

        @Override
        public void run(String... args) {
            logger.info("applicationTest:" + applicationTest);
            logger.info("rpcTest:" + rpcTest);
        }

    }
}

运行后,日志如下:

2024-06-05T15:33:04.284+08:00  INFO 12180 --- [           main] ignameApplication$ValueCommandLineRunner : applicationTest:hahaha
2024-06-05T15:33:04.284+08:00  INFO 12180 --- [           main] ignameApplication$ValueCommandLineRunner : rpcTest:yeah

7. 配置加载顺序

参考SpringBoot 中文文档

  • 命令行参数

  • 特定的应用程序属性,默认如下,详见上方参考文档

    • 当前目录的/config子目录

    • 当前目录

    • Classpath/config

    • Classpath 根

  • 打包Jar之外的指定配置文件(application-{profile}.properties和 YAML 变体

  • 打包jar之内的指定配置文件(application-{profile}.properties和 YAML 变体

  • @Configuration个类上的 @PropertySource 条 Comments。

  • 默认属性(通过设置SpringApplication.setDefaultProperties指定)。