Java框架快速入门: Spring Security+OAuth2之环境配置与多环境部署

纲要

  • 环境与 Profile 概念解析
  • 多环境配置架构
    • application.yml 作为公共配置
    • application-{profile}.yml 实现环境隔离
  • 环境变量读取与默认值设置
  • 数据库等中间件的差异化配置
  • 激活 Profile 的多种方式
    • 配置文件内 spring.profiles.active
    • 环境变量控制
    • IDE 启动参数指定
  • 生产环境安全实践
    • 禁止自动 DDL
    • 敏感信息外部化
    • 日志精简化
  • 基于 Docker 的 MySQL 环境搭建
  • 完整可运行示例

环境与环境变量概述

在 Spring 生态中,一个应用往往需要运行在不同的上下文里:开发者在本地使用 localhost:8080 进行调试,测试团队在专有服务器上验证功能,最终交付到生产环境供真实用户访问。这些上下文就是所谓的"环境"。除了开发(dev)、测试(test)、生产(prod)三大基础环境外,企业还可能引入预发布(staging)、持续集成(CI)等环境。

Spring 为此提供了 Profile 机制,允许开发者将不同环境下的配置拆分成独立文件,并通过灵活的激活方式在运行时切换,从而避免硬编码或重复修改配置。

多配置文件结构

一个典型的 Spring Boot 项目会包含以下配置层次:

dir 复制代码
src/main/resources/
├── application.yml          # 各环境通用配置
├── application-dev.yml      # 开发环境
├── application-test.yml     # 测试环境
└── application-prod.yml     # 生产环境
  • application.yml :存放所有环境共享的属性,比如应用名称、某些固定的日志级别、公共的 message 配置等。
  • application-{profile}.yml :按照环境后缀拆分,如 application-dev.yml,仅写入该环境特有的或需要覆盖的配置。

示例

yml 复制代码
# application.yml (公共部分)
spring:
  application:
    name: security-oauth2-demo
  messages:
    basename: i18n/messages
server:
  port: 8080
yml 复制代码
# application-dev.yml
spring:
  datasource:
    url: jdbc:h2:mem:testdb
    driver-class-name: org.h2.Driver
    username: sa
    password:
  jpa:
    show-sql: true
    hibernate:
      ddl-auto: update
  devtools:
    restart:
      enabled: true
debug: true
yml 复制代码
# application-prod.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/security?useSSL=false&serverTimezone=UTC
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: ${DB_USER:prod_user}
    password: ${DB_PASSWORD}
  jpa:
    show-sql: false
    hibernate:
      ddl-auto: none
  devtools:
    restart:
      enabled: false
logging:
  level:
    root: WARN

从以上配置可以看出,开发环境使用了嵌入式 H2 数据库并开启 SQL 显示,而生产环境连接 MySQL 且关闭了 DDL 自动更新和详细日志,这些都是符合环境职责的配置。

使用环境变量注入敏感信息

application-prod.yml 中,数据库用户名和密码采用了 ${DB_USER:prod_user} 的形式。其含义是:

  • 优先读取操作系统环境变量 DB_USER 的值;
  • 若该环境变量不存在,则使用默认值 prod_user

这样的设计带来了两个明显好处:

  1. 一次构建,多处部署:同一份 jar 包分发到不同主机时,只要各主机预先设置好对应的环境变量,应用就能自动适配,无需修改配置文件。
  2. 安全隔离:生产数据库密码、API 密钥等敏感信息不会出现在代码仓库中。运维人员仅负责在服务器上设置环境变量,开发人员无权限接触生产机密。

同样,激活哪个 Profile 也可以通过环境变量动态指定:

yml 复制代码
spring:
  profiles:
    active: ${SPRING_PROFILES_ACTIVE:dev}

如果系统变量 SPRING_PROFILES_ACTIVE 未设置,则默认激活 dev 环境。

激活 Profile 的三种方式

实际开发中,我们可以根据需要选择激活方式:

  1. 配置文件直接写入(适合本地固定环境):

    yml 复制代码
    spring:
      profiles:
        active: dev
  2. 环境变量动态注入(适合容器化部署):

    bash 复制代码
    export SPRING_PROFILES_ACTIVE=prod
    java -jar app.jar
  3. IDE 运行配置 (IntelliJ IDEA):

    Run/Debug Configurations 的 Spring Boot 启动项中,于 Active profiles 输入框填写目标环境,如 prod

数据库环境差异与初始化脚本

开发环境通常允许自动建表,并可以执行 data.sqlschema.sql 来初始化数据。但在生产环境中,这种做法必须被禁止:

  • spring.jpa.hibernate.ddl-auto 设为 none,防止表结构被意外修改。
  • spring.sql.init.mode 仅在嵌入式数据库时默认执行脚本,对外部数据库建议手动管理。

如果项目需要对接生产库,应通过 SQL 脚本在受控流程中建表:

sql 复制代码
CREATE TABLE users (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    username VARCHAR(50) NOT NULL,
    password VARCHAR(200) NOT NULL,
    enabled BOOLEAN NOT NULL DEFAULT TRUE
);

CREATE TABLE roles (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(50) NOT NULL
);

通过数据库客户端或 Flyway/Liquibase 等迁移工具执行,确保表结构与实体映射保持一致。

Docker 快速搭建 MySQL 环境

为了方便本地验证生产环境的配置,我们使用 Docker Compose 启动一个 MySQL 实例:

yml 复制代码
# docker-compose.yml
version: '3.8'
services:
  mysql:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: root123
      MYSQL_DATABASE: security
      MYSQL_USER: user
      MYSQL_PASSWORD: password
    ports:
      - "3306:3306"
    volumes:
      - mysql_data:/var/lib/mysql
    command: --default-authentication-plugin=mysql_native_password
volumes:
  mysql_data:

启动命令:

bash 复制代码
docker-compose up -d

待容器就绪后,使用数据库工具连接 localhost:3306,执行建表及初始数据脚本。

完整示例:Spring Security + OAuth2 多环境启动

以下是一个整合了 Spring Security 与 OAuth2 授权服务的配置片段,展示如何根据 Profile 控制安全策略。开发环境为了方便测试可能关闭某些安全拦截,而生产环境严格启用。

java 复制代码
// SecurityConfig.java
package com.example.security.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Bean
    @Profile("dev")
    public SecurityFilterChain devFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .anyRequest().permitAll()
            )
            .csrf().disable();
        return http.build();
    }

    @Bean
    @Profile("prod")
    public SecurityFilterChain prodFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/oauth/token").permitAll()
                .anyRequest().authenticated()
            )
            .oauth2ResourceServer().jwt();
        return http.build();
    }
}

启动应用前,确认激活的 Profile 与数据库已正确配置。若激活 prod,则应用连接 MySQL 并加载生产级安全规则;若为 dev,则使用 H2 并开放所有端点。

环境差异对比

配置项 开发环境 生产环境
数据库类型 H2 嵌入式 MySQL 8.0
DDL 策略 update none
SQL 日志 true false
DevTools 启用 禁用
日志级别 DEBUG WARN
安全策略 全部放行(方便调试) 基于 OAuth2 资源服务器严格认证

流程总结

下面用 Mermaid 时序图展示一次部署切换 Profile 并读取环境变量的过程:
数据库 操作系统环境变量 Spring Boot 应用 开发者 数据库 操作系统环境变量 Spring Boot 应用 开发者 #mermaid-svg-40cIXoDRWRKKoGAk{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-40cIXoDRWRKKoGAk .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-40cIXoDRWRKKoGAk .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-40cIXoDRWRKKoGAk .error-icon{fill:#552222;}#mermaid-svg-40cIXoDRWRKKoGAk .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-40cIXoDRWRKKoGAk .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-40cIXoDRWRKKoGAk .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-40cIXoDRWRKKoGAk .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-40cIXoDRWRKKoGAk .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-40cIXoDRWRKKoGAk .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-40cIXoDRWRKKoGAk .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-40cIXoDRWRKKoGAk .marker{fill:#333333;stroke:#333333;}#mermaid-svg-40cIXoDRWRKKoGAk .marker.cross{stroke:#333333;}#mermaid-svg-40cIXoDRWRKKoGAk svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-40cIXoDRWRKKoGAk p{margin:0;}#mermaid-svg-40cIXoDRWRKKoGAk .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-40cIXoDRWRKKoGAk text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-40cIXoDRWRKKoGAk .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-40cIXoDRWRKKoGAk .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-40cIXoDRWRKKoGAk .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-40cIXoDRWRKKoGAk .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-40cIXoDRWRKKoGAk #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-40cIXoDRWRKKoGAk .sequenceNumber{fill:white;}#mermaid-svg-40cIXoDRWRKKoGAk #sequencenumber{fill:#333;}#mermaid-svg-40cIXoDRWRKKoGAk #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-40cIXoDRWRKKoGAk .messageText{fill:#333;stroke:none;}#mermaid-svg-40cIXoDRWRKKoGAk .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-40cIXoDRWRKKoGAk .labelText,#mermaid-svg-40cIXoDRWRKKoGAk .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-40cIXoDRWRKKoGAk .loopText,#mermaid-svg-40cIXoDRWRKKoGAk .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-40cIXoDRWRKKoGAk .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-40cIXoDRWRKKoGAk .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-40cIXoDRWRKKoGAk .noteText,#mermaid-svg-40cIXoDRWRKKoGAk .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-40cIXoDRWRKKoGAk .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-40cIXoDRWRKKoGAk .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-40cIXoDRWRKKoGAk .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-40cIXoDRWRKKoGAk .actorPopupMenu{position:absolute;}#mermaid-svg-40cIXoDRWRKKoGAk .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-40cIXoDRWRKKoGAk .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-40cIXoDRWRKKoGAk .actor-man circle,#mermaid-svg-40cIXoDRWRKKoGAk line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-40cIXoDRWRKKoGAk :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 启动命令 java -jar app.jar 读取 SPRING_PROFILES_ACTIVE 返回 prod 激活 prod profile 读取 DB_USER, DB_PASSWORD 返回对应值 使用读取的凭据连接 连接成功 加载 application-prod.yml 配置 启动完成,提供 OAuth2 认证服务

总结

本文基于 Spring Security + OAuth2 的项目背景,深入讲解了如何利用 Spring 的 Profile 机制实现多环境配置分离,并结合环境变量保证敏感信息的安全性与部署的灵活性。

从配置文件结构、Profile 激活方式,到数据库差异化和 Docker 化基础设施,完整覆盖了从开发到生产的全链路实践。理解并合理运用这些能力,是构建健壮、可维护的企业级 Java 应用的重要一步。

相关推荐
小羊没烦恼!1 小时前
Office文件的奥秘——.NET平台下不借助Office实现Word、Powerpoint等文件的解析(完)
java·大数据·前端·网络·word·powerpoint·.net
小灰灰搞电子1 小时前
Rust suppaftp 库详解:基于 FTP 客户端实战指南
开发语言·后端·rust
编码浪子1 小时前
Rust unsafe 与 FFI 互操作生产级实战:把危险关进笼子的四道闸门
开发语言·后端·rust
估值探索者1 小时前
【AI+量化实战 #05】财报季的信息洪流:用LLM给业绩预告分类+算事件窗口收益
java·c语言·c++·人工智能·python·分类·数据挖掘
热爱编程的小李2 小时前
基于若以开发的新版情怀麻将后台
java
zhanghaha13144 小时前
HTML系列教程:14_HTML 表单与输入框 <form>、<input> 零基础详解
java·前端·javascript
傻啦嘿哟9 小时前
某招聘平台爬虫:爬取招聘岗位数据,分析各城市薪资水平
开发语言·爬虫·python
2501_933670799 小时前
2026秋招量化分析岗技能栈:Python、SQL、统计建模、回测项目怎么准备
开发语言·python·sql
yxlalm9 小时前
Spring AI+RAG 01-项目背景与技术选型
java·人工智能·spring