配置信息防泄露方案:.env 环境隔离详解(dotenv-java)

配置信息防泄露方案:.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-xxxxxxxxxxxxxxxx

2.3 .env 的核心优势

优势说明
无侵入独立文件存在,改配置不动代码
跨语言通用Java、Python、Node.js、Go 都有对应库
关注点分离配置与业务代码解耦
安全隔离.env加入.gitignore,敏感信息不进版本库

2.4 各语言对应库

语言库名
Javadotenv-java
Node.jsdotenv
Pythonpython-dotenv
Gogodotenv

三、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:放敏感、环境相关配置,不进 Git
  • application.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+ 密钥轮换