前言
微服务项目里,数据库密码、大模型 API Key 等敏感信息如果写在 application.properties 并提交到 Git,极易造成泄露。本文介绍一种轻量方案:用 .env 文件 做环境隔离,配合 Java 生态的 dotenv-java 库安全加载配置。
一、需求背景
1.1 硬编码配置的问题
// 反例:配置直接写在代码里
String dbUrl = "jdbc:mysql://localhost:3306/db";
| 问题 | 说明 |
|---|---|
| 违反开闭原则 | 改配置就要改代码、重新部署 |
| 多人协作冲突 | 每人本地环境不同,容易互相覆盖 |
| 环境切换困难 | 开发、测试、生产要频繁改代码 |
1.2 敏感信息暴露的风险
application.properties 中常包含:
- 数据库账号密码
- 大模型 API Key
- OSS 密钥
- 第三方服务 Token
一旦误提交 Git,后果严重:
| 风险 | 说明 |
|---|---|
| 安全泄露 | 公开仓库可被爬取密钥 |
| 黑客攻击 | 密钥被滥用,产生费用或数据泄露 |
| 合规风险 | 金融、医疗等行业有严格安全要求 |
| 协作混乱 | 多人项目应各自维护本地密钥,不能外传 |
二、解决方案:.env 文件
2.1 什么是 .env 文件?
.env 是一种轻量配置格式,用 KEY=VALUE 键值对存储配置:
- 将配置与代码分离
- 集中管理环境变量
- 跨环境、跨语言通用
- 语法简单,无需像
.properties那样转义,也不像.yaml那样严格要求缩进
2.2 .env 文件示例
# .env 文件内容
DB_URL=jdbc:mysql://localhost:3306/mydb
DB_USER=root
DB_PASS=123456 # 数据库密码(支持注释)
APP_PORT=8080
# AI 相关配置示例
LLM_API_KEY=sk-xxxxxxxxxxxxxxxx
LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
EMBEDDING_API_KEY=sk-xxxxxxxxxxxxxxxx
2.3 .env 的核心优势
| 优势 | 说明 |
|---|---|
| 无侵入 | 独立文件存在,改配置不动代码 |
| 跨语言通用 | Java、Python、Node.js、Go 都有对应库 |
| 关注点分离 | 配置与业务代码解耦 |
| 安全隔离 | .env 加入 .gitignore,敏感信息不进版本库 |
2.4 各语言对应库
| 语言 | 库名 |
|---|---|
| Java | dotenv-java |
| Node.js | dotenv |
| Python | python-dotenv |
| Go | godotenv |
三、Java 实现:dotenv-java 库
3.1 为什么用 dotenv-java?
传统 FileReader 手动读取配置:
- 要自己处理空格、空行、注释
- 容易出错
- 没有类型安全和默认值
- 缺少必填校验
dotenv-java 可以自动完成这些事。
3.2 Maven 依赖
<dependency>
<groupId>io.github.cdimascio</groupId>
<artifactId>dotenv-java</artifactId>
<version>3.0.0</version>
</dependency>
3.3 核心特性
① 环境变量兼容
优先读取系统环境变量,没有再读 .env 文件,方便 Docker/K8s 部署。
② 类型安全与默认值
// 获取配置,不存在时使用默认值
String port = dotenv.get("APP_PORT", "8080");
③ 自动加载
默认从项目根目录加载 .env 文件。
④ 自定义路径
// 加载指定环境的配置文件
Dotenv dotenv = Dotenv.configure()
.directory("./config")
.filename(".env.dev")
.load();
⑤ 必填校验
// 关键配置缺失时直接报错,防止带病启动
String dbPass = dotenv.get("DB_PASS");
// 或使用 required 强制校验
dotenv.entries().forEach(entry -> {
// 启动时检查必要配置
});
四、项目目录结构建议
project-root/
├── src/
├── config/
│ ├── .env.dev # 开发环境(不提交 Git)
│ ├── .env.test # 测试环境(不提交 Git)
│ └── .env.prod # 生产环境(不提交 Git)
├── .env.example # 配置模板(提交 Git,无真实密钥)
├── .gitignore # 忽略 .env 文件
└── pom.xml
.gitignore 配置
# 忽略所有真实环境配置
.env
.env.*
!.env.example
# 或者精确忽略
config/.env.dev
config/.env.test
config/.env.prod
.env.example 模板(可提交 Git)
# 数据库配置
DB_URL=jdbc:mysql://localhost:3306/mydb
DB_USER=your_username
DB_PASS=your_password
# 应用配置
APP_PORT=8080
# AI 大模型配置
LLM_API_KEY=your_api_key_here
LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1
LLM_MODEL=qwen-plus
# Embedding 配置
EMBEDDING_API_KEY=your_embedding_key_here
EMBEDDING_MODEL=text-embedding-v4
# OSS 配置
OSS_ENDPOINT=your_endpoint
OSS_ACCESS_KEY=your_access_key
OSS_SECRET_KEY=your_secret_key
五、与 Spring Boot 集成思路
5.1 加载时机
在 Spring Boot 启动类或配置类中,早于 application.yml 加载 .env,将值注入系统属性或自定义配置源。
5.2 配置优先级建议
系统环境变量(最高)
↓
.env 文件
↓
application-{profile}.yml
↓
application.yml(最低)
5.3 典型使用场景
| 配置项 | 存放位置 | 原因 |
|---|---|---|
| 数据库密码 | .env |
敏感 |
| 大模型 API Key | .env |
敏感 |
| OSS 密钥 | .env |
敏感 |
| 服务端口 | .env 或 yml |
环境相关 |
| 业务开关 | application.yml |
非敏感 |
| 日志级别 | application.yml |
非敏感 |
六、多环境隔离方案
6.1 按环境分文件
| 环境 | 文件 | 部署位置 |
|---|---|---|
| 本地开发 | config/.env.dev |
开发者本机 |
| 测试环境 | config/.env.test |
测试服务器 |
| 生产环境 | config/.env.prod |
生产服务器 |
6.2 启动时指定环境
# 开发环境
java -jar app.jar --spring.profiles.active=dev
# 通过环境变量指定 dotenv 文件
export DOTENV_FILE=config/.env.prod
java -jar app.jar
6.3 Docker 部署
# docker-compose.yml
services:
app:
image: my-app:latest
env_file:
- config/.env.prod # 生产配置不入镜像
ports:
- "8080:8080"
七、安全最佳实践
| 实践 | 说明 |
|---|---|
.env 永不提交 Git |
加入 .gitignore |
提供 .env.example |
只含字段名和占位符 |
| 生产密钥独立管理 | 每台服务器单独配置 |
| 定期轮换密钥 | API Key、数据库密码定期更换 |
| 最小权限原则 | 数据库账号只给必要权限 |
| 启动时校验必填项 | 缺关键配置直接失败 |
| 日志脱敏 | 打印配置时屏蔽密码和 Key |
八、常见问题
Q1:.env 和 application.yml 有什么区别?
.env:放敏感、环境相关配置,不进 Gitapplication.yml:放非敏感、业务相关配置,可进 Git
Q2:团队新人如何知道要配哪些项?
提供 .env.example,README 中说明复制为 .env.dev 并填写。
Q3:生产环境怎么用?
- 服务器上放
config/.env.prod - 或通过 K8s Secret / 云平台密钥管理注入
- 不要把生产密钥打进 Docker 镜像
Q4:已有 application.yml 还要 .env 吗?
建议敏感项迁到 .env,非敏感项保留在 yml,两者配合使用。
九、知识点总结
| 要点 | 内容 |
|---|---|
| 核心问题 | 硬编码配置 + 敏感信息进 Git |
| 解决方案 | .env 文件 + dotenv-java |
| 关键原则 | 配置与代码分离、敏感信息不进版本库 |
| Java 工具 | dotenv-java 自动加载、默认值、必填校验 |
| 多环境 | .env.dev / .env.test / .env.prod |
| 安全实践 | .gitignore + .env.example + 密钥轮换 |