核心是构建或启动时自动注入环境变量,而非手动修改配置。java用maven profile+资源过滤在打包阶段写入;前端通过.env文件在构建时硬编码;python/node.js/go在启动时读取校验;系统级通过shell函数或独立账户隔离环境。
核心是让构建或启动过程自动注入对应环境的变量值,而不是靠人手动改配置文件。关键不在于“存哪里”,而在于“谁在什么时候把哪个值塞进去”。不同技术栈实现路径不同,但逻辑一致:定义环境标识 → 组织变量来源 → 在正确时机完成替换。
Java(Maven + Spring Boot):打包时 baked-in
用 Maven Profile + 资源过滤,在 mvn package 阶段就把变量值写进最终 JAR 包里:
- 在
pom.xml中声明<profile></profile>,比如<id>dev</id>和<id>prod</id>,每个 profile 设置<deploy.type>dev</deploy.type>这类属性 - 按 profile 名建目录:
src/main/resources.dev/和src/main/resources.prod/,放各自专属配置(如数据库地址、开关) - 在
<build><resources></resources></build>中启用<filtering>true</filtering>,并动态加载src/main/resources.${deploy.type} -
application.yml里写spring.profiles.active: @deploy.type@,Maven 构建时自动替换成dev或prod
前端(Vite / Vue CLI / Umi):构建时注入常量
变量在编译阶段被硬编码进 JS,运行时不可变,安全且高效:
- 创建
.env.development、.env.production等文件,内容以VITE_APP_(Vite)或VUE_APP_(Vue CLI)开头 - Vite 会自动加载匹配当前
--mode的 .env 文件;Umi 则通过UMI_ENV=prod umi build加载.umirc.prod.js - 代码中直接使用
import.meta.env.VITE_APP_API_URL,构建后变成字符串字面量,不会暴露原始变量名 - 注意:不能用
process.env.NODE_ENV存业务配置,它只反映构建目标,不是运行时环境
Python / Node.js / Go:启动时读取并校验
变量在进程启动瞬间加载,由程序主动控制解析逻辑和 fallback 行为:
- Python 用
python-dotenv在入口第一行调用load_dotenv(".env." + os.getenv('ENV', 'development')) - Node.js 用
dotenv.config({ path: `.env.${process.env.NODE_ENV}` }),配合cross-env NODE_ENV=production npm start - Go 封装
Env()函数:先os.Getenv("GO_ENV"),为空则设默认"development",再统一转小写;敏感字段(如密钥)为空直接log.Fatal - 所有语言都禁用“自动映射全部环境变量”的机制(如 Viper 的
AutomaticEnv()),只显式绑定带前缀的变量(如APP_DB_HOST)
系统级(macOS/Linux):按会话或账户隔离作用域
避免全局污染,确保不同终端互不影响:
- 在
~/.zshrc里定义dev_env()和prod_env()函数,执行后仅当前终端生效 - 生产部署用独立系统账户(如
myapp-prod),其~/.zshrc只含生产变量,物理隔离最稳妥 - 项目根目录放
.env.development,配合 shell 工具(如direnv)进入目录自动加载,退出自动清理 - GUI 应用(如 VS Code)需额外配置,确保它继承的是你激活的环境,而不是登录时的默认 shell 环境











