java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringBoot多环境配置

SpringBoot多环境配置踩坑指南

作者:神奇小汤圆

这篇文章主要为大家详细介绍了SpringBoot多环境配置的相关方法和避坑指南,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下

先说说我的项目情况

我目前维护的项目用的是 Spring Boot 2.5.15,配置文件的组织方式是这样的:

resources/config/dev/hbase.properties
resources/config/dev/zk.properties
resources/config/dev/hbase.xml
resources/config/prod/hbase.properties
resources/config/prod/zk.properties
resources/config/prod/hbase.xml

代码里也是五花八门:有用 @Value 注入的,有用 @ConfigurationProperties 的,还有硬编码用 ClassLoader.getResourceAsStream() 读取的。说实话,这种”历史遗留”代码,懂的都懂。

最近研究配置加载方式的时候,发现门道还挺多。今天就结合自己的理解,把这几个常用参数彻底掰扯清楚。

一、-Xbootclasspath/a:JVM 级别的”后门”

这玩意儿到底干嘛的?

简单来说,这是 JVM 的标准参数,用来在 Bootstrap ClassLoader 的搜索路径末尾追加额外的类路径。Bootstrap ClassLoader 是 JVM 最顶层的类加载器,负责加载核心类库。

我什么时候用它?

主要是为了解决那种需要从 ClassLoader 直接读取配置文件的场景。比如我项目里那些用 getResourceAsStream("xxx.properties") 的代码,如果不加这个参数,有时候就读不到外部配置文件。

用法示例

# Linux/Mac
java -Xbootclasspath/a:/path/to/config -jar app.jar
# Windows(注意用分号)
java -Xbootclasspath/a:C:\path\to\config -jar app.jar

踩坑提醒

二、-Dloader.path:Spring Boot 可执行 Jar 的专属武器

原理是啥?

这个参数是 Spring Boot 的 LaunchedURLClassLoader 专门识别的。当你打包成 Fat Jar 后,Spring Boot 会用自己定制的 ClassLoader 来加载类,而这个参数就是告诉它:”嘿,除了这些,再去这些地方找找”。

我能用它干嘛?

用法示例

# Linux/Mac
java -Dloader.path=/path/to/config,/path/to/lib -jar app.jar
# Windows
java -Dloader.path=C:\path\to\config;C:\path\to\lib -jar app.jar

实际应用场景

我现在的启动脚本就是这样写的:

java -Dloader.path=/opt/myapp/config \
     -Dspring.profiles.active=prod \
     -jar myapp.jar

这样配置文件就可以放在 jar 包外面,改配置不用重新打包,运维同学也很开心。

三、spring.config.location:彻底接管配置加载

注意!这是”替换”不是”追加”

这个参数会完全覆盖 Spring Boot 默认的配置文件搜索位置。默认情况下,Spring Boot 会按这个顺序找配置:

一旦你用了 spring.config.location,上面这些位置就都被忽略了,只加载你指定的位置。

三种设置方式

# 1. 命令行参数(优先级最高)
java -jar app.jar --spring.config.location=/path/to/config/
# 2. 系统属性
java -Dspring.config.location=/path/to/config/ -jar app.jar
# 3. 环境变量
export SPRING_CONFIG_LOCATION=/path/to/config/

我的建议

除非你有特殊需求,否则不要轻易用这个参数。一旦用了,默认的配置加载逻辑就全被 干掉了,很容易踩坑。

四、spring.config.additional-location:更友好的”追加”方式

和上面的区别

这个参数是追加而不是替换。它会在默认配置位置的基础上,额外增加你指定的搜索路径。

优先级顺序

这是我目前最推荐的方式

java -jar app.jar --spring.config.additional-location=/opt/myapp/config/

这样既保留了 Spring Boot 的默认行为,又能加载外部的配置文件,两全其美。

五、配置加载优先级:一定要搞清楚

Spring Boot 的配置属性优先级从高到低:

记住这个优先级很重要,有时候配置没生效,很可能就是优先级被覆盖了。

六、我的项目改造实录

原来的问题

我项目里有一堆这样的代码:

InputStream is = HbaseConfig.class.getClassLoader()
    .getResourceAsStream("hbase.properties");

这种写法有几个问题:

改造方案

方案一:使用 Spring 的 ResourceLoader(推荐)

@Autowired
private ResourceLoader resourceLoader;
public void loadConfig() throws IOException {
    Resource resource = resourceLoader.getResource(
        "classpath:config/" + env + "/hbase.properties"
    );
    Properties props = new Properties();
    props.load(resource.getInputStream());
}

方案二:直接用 @Value 注入

@Value("classpath:config/${spring.profiles.active}/hbase.properties")
private Resource hbaseConfig;

方案三:彻底拥抱 Spring Boot(最佳)

把配置文件内容合并到 application-dev.yml 和 application-prod.yml 中,完全交给 Spring Boot 管理。

七、各环境的最佳实践

开发环境(IDE 中运行)

项目结构:

project/
├── src/main/resources/
│   ├── application.yml          # 主配置
│   ├── application-dev.yml      # 开发环境
│   ├── application-prod.yml     # 生产环境
│   └── config/
│       ├── dev/
│       └── prod/
└── external-config/             # 外部配置(gitignore)
    └── application-local.yml    # 个人本地配置

IDE 启动参数:

-Dspring.profiles.active=dev
-Dspring.config.additional-location=file:./external-config/

Linux 生产环境

目录结构:

/opt/myapp/
├── app.jar
├── config/
│   ├── application.yml
│   ├── hbase.properties
│   └── zk.properties
└── logs/

启动脚本:

#!/bin/bash
APP_HOME=/opt/myapp
CONFIG_DIR=$APP_HOME/config
LOG_DIR=$APP_HOME/logs
mkdir -p $LOG_DIR
java \
  -Dspring.profiles.active=prod \
  -Dspring.config.additional-location=file:$CONFIG_DIR/ \
  -Dloader.path=$CONFIG_DIR \
  -Xms512m \
  -Xmx1024m \
  -jar $APP_HOME/app.jar \
  >> $LOG_DIR/app.log 2>&1 &
echo $! > $APP_HOME/app.pid

Systemd 服务配置:

[Unit]
Description=My Spring Boot Application
After=syslog.target
[Service]
User=appuser
WorkingDirectory=/opt/myapp
Environment="SPRING_PROFILES_ACTIVE=prod"
Environment="SPRING_CONFIG_ADDITIONAL_LOCATION=file:/opt/myapp/config/"
ExecStart=/usr/bin/java -jar /opt/myapp/app.jar
Restart=on-failure
[Install]
WantedBy=multi-user.target

Windows 生产环境

目录结构:

C:\Apps\MyApp\
├── app.jar
├── config\
│   ├── application.yml
│   ├── hbase.properties
│   └── zk.properties
└── start.bat

启动脚本:

@echo off
setlocal

set APP_HOME=C:\Apps\MyApp
set CONFIG_DIR=%APP_HOME%\config

java ^
  -Dspring.profiles.active=prod ^
  -Dspring.config.additional-location=file:%CONFIG_DIR%/ ^
  -Dloader.path=%CONFIG_DIR% ^
  -Xms512m ^
  -Xmx1024m ^
  -jar %APP_HOME%\app.jar

endlocal

八、最后:我的选择建议

场景推荐参数原因
开发环境spring.config.additional-location保留默认行为,方便调试
生产环境(Linux)spring.config.additional-location + loader.path灵活、可控
生产环境(Windows)spring.config.additional-location + loader.path同上
需要 ClassLoader 读取-Xbootclasspath/a兼容遗留代码
完全自定义配置位置spring.config.location特殊需求专用

最后说一句:不要过度设计。对于大部分项目来说,spring.config.additional-location 配合 spring.profiles.active 已经够用了。除非你真的有特殊需求,否则没必要搞得太复杂。

到此这篇关于SpringBoot多环境配置踩坑指南的文章就介绍到这了,更多相关SpringBoot多环境配置内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文