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.sql 或 schema.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 应用的重要一步。

相关推荐
三84427 分钟前
Fastjson 漏洞 · 02 · autoType 机制与 checkAutoType
java·fastjson
悠仁さん30 分钟前
【C++】vector 类
开发语言·c++
_upupup40 分钟前
智能指针的原理及简单模拟实现(C++)
开发语言·c++
en.en..1 小时前
C语言---宏
c语言·开发语言
无限码力1 小时前
小红书笔试真题 9.17 - 待发热度重排(C++/Py/Java /Js/Go)
java·小红书·小红书笔试真题·小红书技术岗笔试真题
郝学胜-神的一滴1 小时前
C++ Templates 01:拨开迷雾,读懂C++模板经典著作
开发语言·c++·程序人生·游戏·游戏引擎·软件构建
卓怡学长1 小时前
w194基于ssm新能源汽车充电系统小程序
java·小程序·intellij-idea
JAVA面经实录9171 小时前
Java高级后端 · 全套面试通关手册(MySQL)
java·mysql·面试
言乐61 小时前
Python实现关税自动计算模型
开发语言·python·django·virtualenv·pygame