配置信息防泄露方案:.env 环境隔离详解(dotenv-java)
前言
微服务项目里,数据库密码、大模型 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-xxxxxxxxxxxxxxxx2.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.jar6.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+ 密钥轮换 |
