Spring Boot多环境配置实践:Profile策略与配置管理

# Spring Boot多环境配置实践:Profile策略与配置管理


在企业级应用开发中,不同环境的配置管理是保障应用稳定运行的关键。Spring Boot Profile机制提供了灵活的配置方案,支持开发、测试、预生产和生产等多环境配置管理。


## Profile基础配置架构


Spring Boot支持多种配置源,通过profile-specific配置文件和环境变量实现配置的动态加载。


```yaml

# application.yml - 基础配置

spring:

  application:

    name: product-service

  config:

    import:

      - optional:file:.env[.properties]

      - optional:file:config/application-{profile}.yml

    activate:

      on-profile: default


# 应用基本信息

app:

  version: 1.0.0

  description: 商品服务

  contact:

    email: support@example.com

    phone: 400-123-4567


# 日志配置

logging:

  level:

    root: INFO

    com.example: DEBUG

    org.springframework.web: INFO

    org.hibernate: WARN

  pattern:

    console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"

    file: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"

  file:

    name: logs/app.log

    max-history: 30

    max-size: 10MB


# Actuator监控端点

management:

  endpoints:

    web:

      exposure:

        include: health,info,metrics

      base-path: /internal


# 默认数据源配置(使用H2内存数据库)

demo:

  datasource:

    url: jdbc:h2:mem:testdb

    driver-class-name: org.h2.Driver

    username: sa

    password: ""

    hikari:

      maximum-pool-size: 5

      connection-timeout: 30000

  jpa:

    hibernate:

      ddl-auto: create-drop

    show-sql: true

    properties:

      hibernate:

        dialect: org.hibernate.dialect.H2Dialect

        format_sql: true


# 缓存配置

demo:

  cache:

    type: simple

    cache-names: products,categories,users

    caffeine:

      spec: maximumSize=100,expireAfterWrite=10m

```


## 多环境配置文件设计


```yaml

# application-dev.yml - 开发环境配置

spring:

  config:

    activate:

      on-profile: dev


# 开发环境数据源

spring:

  datasource:

    url: jdbc:mysql://localhost:3306/product_dev?useSSL=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8&allowPublicKeyRetrieval=true

    driver-class-name: com.mysql.cj.jdbc.Driver

    username: dev_user

    password: dev_password

    hikari:

      maximum-pool-size: 10

      minimum-idle: 3

      connection-timeout: 30000

      idle-timeout: 600000

      max-lifetime: 1800000

      connection-test-query: SELECT 1

  

  # JPA配置

  jpa:

    hibernate:

      ddl-auto: update

    show-sql: true

    properties:

      hibernate:

        dialect: org.hibernate.dialect.MySQL8Dialect

        format_sql: true

        jdbc:

          batch_size: 20

        order_inserts: true

        order_updates: true

    open-in-view: false

  

  # Redis配置

  redis:

    host: localhost

    port: 6379

    password: ""

    database: 0

    timeout: 5000ms

    lettuce:

      pool:

        max-active: 8

        max-idle: 8

        min-idle: 0

        max-wait: -1ms

      shutdown-timeout: 100ms

  

  # 消息队列配置

  rabbitmq:

    host: localhost

    port: 5672

    username: guest

    password: guest

    virtual-host: /

    connection-timeout: 10000

    listener:

      simple:

        concurrency: 3

        max-concurrency: 10

        prefetch: 10

        retry:

          enabled: true

          max-attempts: 3

          initial-interval: 1000ms

  

  # 邮件配置

  mail:

    host: smtp.gmail.com

    port: 587

    username: dev@example.com

    password: ${MAIL_PASSWORD:dev_password}

    properties:

      mail:

        smtp:

          auth: true

          starttls:

            enable: true

          connectiontimeout: 5000

          timeout: 5000

          writetimeout: 5000


# 应用特定配置

app:

  environment: dev

  features:

    enable-cache: true

    enable-notification: false

    enable-audit-log: true

    api-rate-limit: 1000

  security:

    cors:

      allowed-origins: "http://localhost:3000,http://localhost:8080"

      allowed-methods: "GET,POST,PUT,DELETE,OPTIONS"

      allowed-headers: "*"

      allow-credentials: true

    jwt:

      secret: dev_jwt_secret_key_change_in_production

      expiration: 86400000  # 24小时

  external:

    payment-service:

      url: http://localhost:8081

      timeout: 5000

    inventory-service:

      url: http://localhost:8082

      timeout: 3000

  monitoring:

    sentry:

      dsn: ${SENTRY_DSN:}

      enabled: false

    new-relic:

      enabled: false


# 日志配置覆盖

logging:

  level:

    com.example: TRACE

    org.springframework.web: DEBUG

    org.hibernate.SQL: DEBUG

    org.hibernate.type: TRACE

  file:

    name: logs/app-dev.log

```


```yaml

# application-test.yml - 测试环境配置

spring:

  config:

    activate:

      on-profile: test


# 测试环境数据源

spring:

  datasource:

    url: jdbc:mysql://test-db.example.com:3306/product_test?useSSL=true&serverTimezone=Asia/Shanghai

    driver-class-name: com.mysql.cj.jdbc.Driver

    username: ${DB_USERNAME:test_user}

    password: ${DB_PASSWORD:test_password}

    hikari:

      maximum-pool-size: 20

      minimum-idle: 5

      connection-timeout: 30000

      idle-timeout: 600000

      max-lifetime: 1800000

  

  jpa:

    hibernate:

      ddl-auto: validate

    show-sql: false

    properties:

      hibernate:

        dialect: org.hibernate.dialect.MySQL8Dialect

        jdbc:

          batch_size: 50

  

  redis:

    host: test-redis.example.com

    port: 6379

    password: ${REDIS_PASSWORD:}

    database: 1

    timeout: 3000ms

    lettuce:

      pool:

        max-active: 20

        max-idle: 10

        min-idle: 5


# 测试环境特定配置

app:

  environment: test

  features:

    enable-cache: true

    enable-notification: true

    enable-audit-log: true

    api-rate-limit: 5000

    enable-mock-payment: true  # 测试环境启用模拟支付

  security:

    cors:

      allowed-origins: "https://test.example.com,https://test-api.example.com"

    jwt:

      secret: ${JWT_SECRET:test_jwt_secret}

      expiration: 3600000  # 1小时

  external:

    payment-service:

      url: https://payment-test.example.com

      timeout: 10000

      retry:

        max-attempts: 3

        backoff-delay: 1000

    inventory-service:

      url: https://inventory-test.example.com

      timeout: 5000

  

  # 测试数据

  test-data:

    enabled: true

    location: classpath:test-data/

    clean-before-load: true

    datasets:

      - users.json

      - products.json

      - orders.json


# 集成测试配置

integration:

  test:

    timeout: 30000

    cleanup:

      enabled: true

      strategy: transaction

    database:

      reset:

        enabled: true

        script: classpath:test-reset.sql

```


```yaml

# application-staging.yml - 预生产环境配置

spring:

  config:

    activate:

      on-profile: staging


# 预生产环境数据源

spring:

  datasource:

    url: jdbc:mysql://staging-db-cluster.example.com:3306/product_staging?useSSL=true&serverTimezone=Asia/Shanghai

    driver-class-name: com.mysql.cj.jdbc.Driver

    username: ${DB_USERNAME}

    password: ${DB_PASSWORD}

    hikari:

      maximum-pool-size: 30

      minimum-idle: 10

      connection-timeout: 30000

      idle-timeout: 600000

      max-lifetime: 1800000

      connection-init-sql: SET NAMES utf8mb4

  

  # 多数据源配置(读写分离)

  datasources:

    read:

      url: jdbc:mysql://staging-db-readonly.example.com:3306/product_staging?useSSL=true

      username: ${DB_READ_USERNAME}

      password: ${DB_READ_PASSWORD}

      hikari:

        maximum-pool-size: 20

        read-only: true

    write:

      url: jdbc:mysql://staging-db-master.example.com:3306/product_staging?useSSL=true

      username: ${DB_WRITE_USERNAME}

      password: ${DB_WRITE_PASSWORD}

      hikari:

        maximum-pool-size: 15

        read-only: false

  

  # 连接池监控

  jpa:

    hibernate:

      ddl-auto: none

    show-sql: false

    properties:

      hibernate:

        stats: true

        generate_statistics: true

        session.events.log: true

  

  # Redis哨兵配置

  redis:

    sentinel:

      master: redis-staging-master

      nodes:

        - staging-redis-sentinel-1:26379

        - staging-redis-sentinel-2:26379

        - staging-redis-sentinel-3:26379

    password: ${REDIS_PASSWORD}

    database: 2

    timeout: 5000ms

    lettuce:

      pool:

        max-active: 50

        max-idle: 20

        min-idle: 10

  

  # 消息队列集群

  rabbitmq:

    addresses: staging-rabbit-1:5672,staging-rabbit-2:5672

    username: ${RABBITMQ_USERNAME}

    password: ${RABBITMQ_PASSWORD}

    virtual-host: /staging

    connection-timeout: 5000

    cache:

      channel:

        size: 25


# 预生产环境应用配置

app:

  environment: staging

  features:

    enable-cache: true

    enable-notification: true

    enable-audit-log: true

    api-rate-limit: 10000

    enable-cdn: true

    enable-compression: true

  security:

    cors:

      allowed-origins: "https://staging.example.com,https://staging-api.example.com"

    jwt:

      secret: ${JWT_SECRET}

      expiration: 7200000  # 2小时

    ssl:

      enabled: true

      protocols: TLSv1.2,TLSv1.3

    rate-limit:

      global: 1000

      per-user: 100

  

  # 外部服务配置

  external:

    payment-service:

      url: https://payment-staging.example.com

      timeout: 15000

      circuit-breaker:

        enabled: true

        failure-threshold: 5

        timeout: 10000

    inventory-service:

      url: https://inventory-staging.example.com

      timeout: 10000

      retry:

        max-attempts: 3

        backoff-multiplier: 2.0

  

  # 性能配置

  performance:

    thread-pool:

      core-size: 10

      max-size: 50

      queue-capacity: 100

    cache:

      ttl: 300

      max-size: 1000

    http:

      max-connections: 100

      timeout: 30000

  

  # 监控配置

  monitoring:

    sentry:

      dsn: ${SENTRY_DSN_STAGING}

      enabled: true

      environment: staging

    new-relic:

      enabled: true

      app-name: product-service-staging

    metrics:

      export-interval: 60s

      retention: 7d


# Actuator扩展配置

management:

  endpoints:

    web:

      exposure:

        include: "*"

    jmx:

      exposure:

        include: "*"

  endpoint:

    health:

      show-details: when-authorized

      probes:

        enabled: true

    metrics:

      export:

        prometheus:

          enabled: true

        datadog:

          enabled: true

          api-key: ${DATADOG_API_KEY}

  metrics:

    tags:

      environment: staging

      region: ${CLOUD_REGION:cn-east-1}

    distribution:

      percentiles-histogram:

        http.server.requests: true

```


```yaml

# application-prod.yml - 生产环境配置

spring:

  config:

    activate:

      on-profile: prod


# 生产环境数据源

spring:

  datasource:

    url: jdbc:mysql://prod-db-cluster.example.com:3306/product_prod?useSSL=true&serverTimezone=Asia/Shanghai&rewriteBatchedStatements=true

    driver-class-name: com.mysql.cj.jdbc.Driver

    username: ${PROD_DB_USERNAME}

    password: ${PROD_DB_PASSWORD}

    hikari:

      maximum-pool-size: 50

      minimum-idle: 20

      connection-timeout: 30000

      idle-timeout: 600000

      max-lifetime: 1800000

      connection-init-sql: SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci

      leak-detection-threshold: 60000

      validation-timeout: 5000

      connection-test-query: SELECT 1 FROM DUAL

  

  # 生产环境多数据源

  datasources:

    read:

      url: jdbc:mysql://prod-db-ro-cluster.example.com:3306/product_prod?useSSL=true

      username: ${PROD_DB_READ_USERNAME}

      password: ${PROD_DB_READ_PASSWORD}

      hikari:

        maximum-pool-size: 40

        minimum-idle: 15

        read-only: true

        connection-timeout: 10000

    write:

      url: jdbc:mysql://prod-db-rw-cluster.example.com:3306/product_prod?useSSL=true

      username: ${PROD_DB_WRITE_USERNAME}

      password: ${PROD_DB_WRITE_PASSWORD}

      hikari:

        maximum-pool-size: 30

        minimum-idle: 10

        read-only: false

        connection-timeout: 15000

  

  # JPA生产配置

  jpa:

    hibernate:

      ddl-auto: validate

    show-sql: false

    properties:

      hibernate:

        dialect: org.hibernate.dialect.MySQL8Dialect

        jdbc:

          batch_size: 100

        order_inserts: true

        order_updates: true

        jdbc.batch_versioned_data: true

        generate_statistics: true

        cache:

          use_second_level_cache: true

          use_query_cache: true

          region.factory_class: org.hibernate.cache.jcache.JCacheRegionFactory

    open-in-view: false

  

  # Redis集群配置

  redis:

    cluster:

      nodes:

        - prod-redis-node-1:6379

        - prod-redis-node-2:6379

        - prod-redis-node-3:6379

        - prod-redis-node-4:6379

        - prod-redis-node-5:6379

        - prod-redis-node-6:6379

      max-redirects: 3

    password: ${PROD_REDIS_PASSWORD}

    timeout: 3000ms

    lettuce:

      pool:

        max-active: 100

        max-idle: 50

        min-idle: 20

        max-wait: 5000ms

      cluster:

        refresh:

          adaptive: true

          period: 30000

  

  # RabbitMQ生产配置

  rabbitmq:

    addresses: prod-rabbit-1:5672,prod-rabbit-2:5672,prod-rabbit-3:5672

    username: ${PROD_RABBITMQ_USERNAME}

    password: ${PROD_RABBITMQ_PASSWORD}

    virtual-host: /prod

    connection-timeout: 10000

    publisher-confirm-type: correlated

    publisher-returns: true

    listener:

      simple:

        concurrency: 5

        max-concurrency: 20

        prefetch: 50

        acknowledge-mode: manual

        retry:

          enabled: true

          max-attempts: 5

          initial-interval: 3000ms

          multiplier: 2.0

  <"j2.p5k3.org.cn"><"n5.p5k3.org.cn"><"w1.p5k3.org.cn">

  # 邮件生产配置

  mail:

    host: smtp.exmail.qq.com

    port: 465

    username: ${PROD_MAIL_USERNAME}

    password: ${PROD_MAIL_PASSWORD}

    protocol: smtps

    properties:

      mail:

        smtp:

          auth: true

          ssl:

            enable: true

          socketFactory:

            class: javax.net.ssl.SSLSocketFactory

          connectiontimeout: 10000

          timeout: 10000

          writetimeout: 10000

  

  # 安全配置

  security:

    oauth2:

      resourceserver:

        jwt:

          issuer-uri: https://auth.example.com

          jwk-set-uri: https://auth.example.com/.well-known/jwks.json


# 生产环境应用配置

app:

  environment: prod

  version: ${APP_VERSION:1.0.0}

  features:

    enable-cache: true

    enable-notification: true

    enable-audit-log: true

    api-rate-limit: 50000

    enable-cdn: true

    enable-compression: true

    enable-gzip: true

    enable-http2: true

    enable-response-cache: true

  security:

    cors:

      allowed-origins: "https://example.com,https://api.example.com"

      allowed-methods: "GET,POST,PUT,DELETE,OPTIONS"

      allowed-headers: "Authorization,Content-Type,X-Requested-With,Accept,Origin"

      exposed-headers: "X-Total-Count,X-Page-Count"

      max-age: 3600

    jwt:

      secret: ${PROD_JWT_SECRET}

      expiration: 3600000  # 1小时

      refresh-expiration: 2592000000  # 30天

    rate-limit:

      enabled: true

      global: 5000

      per-user: 200

      per-ip: 1000

    ssl:

      enabled: true

      protocols: TLSv1.3

      ciphers: TLS_AES_256_GCM_SHA384,TLS_CHACHA20_POLY1305_SHA256

  

  # 外部服务生产配置

  external:

    payment-service:

      url: https://payment.example.com

      timeout: 30000

      circuit-breaker:

        enabled: true

        failure-threshold: 10

        timeout: 20000

        reset-timeout: 60000

      retry:

        max-attempts: 3

        backoff:

          delay: 1000

          multiplier: 2.0

          max-delay: 10000

    inventory-service:

      url: https://inventory.example.com

      timeout: 20000

      load-balancer:

        strategy: round-robin

        health-check:

          enabled: true

          interval: 30000

  

  # 性能优化配置

  performance:

    thread-pool:

      core-size: 20

      max-size: 100

      queue-capacity: 200

      keep-alive-time: 60s

    cache:

      ttl: 600

      max-size: 10000

      caffeine:

        spec: maximumSize=10000,expireAfterWrite=600s

    http:

      client:

        max-connections: 200

        max-connections-per-route: 50

        connection-timeout: 10000

        socket-timeout: 30000

        connection-request-timeout: 10000

      server:

        max-threads: 200

        min-spare-threads: 20

        connection-timeout: 30000

        max-connections: 10000

        max-http-header-size: 16KB

        compression:

          enabled: true

          mime-types: text/html,text/xml,text/plain,text/css,text/javascript,application/json,application/javascript,application/xml

          min-response-size: 1024

  

  # 监控告警配置

  monitoring:

    sentry:

      dsn: ${PROD_SENTRY_DSN}

      enabled: true

      environment: production

      release: ${APP_VERSION}

      traces-sample-rate: 0.1

    new-relic:

      enabled: true

      app-name: product-service-prod

      license-key: ${NEW_RELIC_LICENSE_KEY}

    datadog:

      enabled: true

      api-key: ${DATADOG_API_KEY}

      site: datadoghq.com

    metrics:

      export-interval: 30s

      retention: 30d

      percentiles: 0.5,0.95,0.99

    alert:

      enabled: true

      webhook: ${ALERT_WEBHOOK_URL}

      rules:

        error-rate:

          threshold: 5%

          window: 5m

        response-time:

          p95-threshold: 2000ms

          window: 10m

        system:

          cpu-threshold: 80%

          memory-threshold: 85%

          disk-threshold: 90%

  

  # 审计日志配置

  audit:

    enabled: true

    level: INFO

    max-size: 100MB

    retention: 90d

    format: json

    include:

      - request

      - response

      - user

      - timestamp

      - duration


# Actuator生产配置

management:

  server:

    port: 8081

    address: 127.0.0.1

    ssl:

      enabled: true

      key-store: classpath:keystore.p12

      key-store-password: ${ACTUATOR_KEYSTORE_PASSWORD}

      key-store-type: PKCS12

  endpoints:

    web:

      exposure:

        include: health,info,metrics,prometheus

      base-path: /internal

      path-mapping:

        health: health-check

      access:

        rules:

          - endpoint: health

            access: unrestricted

          - endpoint: info

            access: authenticated

          - endpoint: metrics

            access: admin

    jmx:

      exposure:

        include: health,info,metrics

      domain: com.example.prod

  endpoint:

    health:

      show-details: when-authorized

      show-components: when-authorized

      roles: ADMIN,OPERATOR

      group:

        liveness:

          include: ping,livenessState,diskSpace

        readiness:

          include: ping,readinessState,db,redis,mq,custom

      probes:

        enabled: true

    metrics:

      enabled: true

      distribution:

        percentiles-histogram:

          http.server.requests: true

          jvm.gc.pause: true

        slo:

          http.server.requests: 100ms,500ms,1s,5s

    prometheus:

      enabled: true

      step: 15s

  metrics:

    export:

      prometheus:

        enabled: true

        step: 15s

      datadog:

        enabled: true

        api-key: ${DATADOG_API_KEY}

        step: 30s

    tags:

      application: product-service

      environment: production

      region: ${CLOUD_REGION}

      zone: ${CLOUD_ZONE}

      instance: ${HOSTNAME:${spring.application.instance-id:${random.value}}}

    distribution:

      percentiles:

        http.server.requests: 0.5,0.95,0.99

      percentiles-histogram:

        http.server.requests: true

        jvm.gc.pause: true

  tracing:

    sampling:

      probability: 0.01

    propagation:

      type: B3,W3C


# 日志生产配置

logging:

  level:

    root: WARN

    com.example: INFO

    org.springframework.web: WARN

    org.hibernate: ERROR

    org.apache.kafka: WARN

    org.springframework.amqp: WARN

  pattern:

    console: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%X{traceId:-},%X{spanId:-}] - %msg%n"

    file: "%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%X{traceId:-},%X{spanId:-}] - %msg%n"

  logback:

    rollingpolicy:

      max-file-size: 100MB

      max-history: 30

      total-size-cap: 3GB

      clean-history-on-start: true

  file:

    name: /var/log/product-service/app.log

  log-dir: /var/log/product-service/

```


## Profile激活与配置覆盖策略


```java

// ProfileConfiguration.java - Profile配置类

package com.example.config;


import org.springframework.boot.SpringApplication;

import org.springframework.boot.env.EnvironmentPostProcessor;

import org.springframework.boot.env.YamlPropertySourceLoader;

import org.springframework.core.env.ConfigurableEnvironment;

import org.springframework.core.env.PropertySource;

import org.springframework.core.io.ClassPathResource;

import org.springframework.core.io.Resource;


import java.io.IOException;

import java.util.Arrays;

import java.util.List;


@Configuration

public class ProfileConfiguration {

    

    // 自定义属性源加载器

    @Component

    public static class CustomEnvironmentPostProcessor implements EnvironmentPostProcessor {

        

        private final YamlPropertySourceLoader loader = new YamlPropertySourceLoader();

        

        @Override

        public void postProcessEnvironment(ConfigurableEnvironment environment, 

                                         SpringApplication application) {

            

            // 根据激活的profiles加载特定配置

            List activeProfiles = Arrays.asList(environment.getActiveProfiles());

            

            // 加载优先级:外部配置 > 环境变量 > 配置文件

            loadProfileSpecificConfig(environment, activeProfiles);

            

            // 加载租户特定配置(多租户场景)

            loadTenantConfig(environment);

            

            // 设置配置验证

            validateConfiguration(environment);

        }

        

        private void loadProfileSpecificConfig(ConfigurableEnvironment environment, 

                                             List activeProfiles) {

            

            // 基础配置

            loadYamlResource(environment, "classpath:application.yml");

            

            // Profile特定配置

            for (String profile : activeProfiles) {

                String configFile = String.format("classpath:application-%s.yml", profile);

                loadYamlResource(environment, configFile);

                

                // 加载可选的本地覆盖配置

                String localConfig = String.format("classpath:application-%s-local.yml", profile);

                loadYamlResourceOptional(environment, localConfig);

            }

            

            // 加载外部配置文件

            String externalConfig = System.getProperty("config.location");

            if (externalConfig != null) {

                loadYamlResource(environment, "file:" + externalConfig);

            }

        }

        

        private void loadTenantConfig(ConfigurableEnvironment environment) {

            String tenantId = environment.getProperty("app.tenant.id");

            if (tenantId != null) {

                String tenantConfig = String.format("classpath:tenant/application-%s.yml", tenantId);

                loadYamlResourceOptional(environment, tenantConfig);

            }

        }

        <"g8.p5k3.org.cn"><"q0.p5k3.org.cn"><"t4.p5k3.org.cn">

        private void loadYamlResource(ConfigurableEnvironment environment, String location) {

            try {

                Resource resource = new ClassPathResource(location.replace("classpath:", ""));

                if (resource.exists()) {

                    List> sources = loader.load(location, resource);

                    sources.forEach(environment.getPropertySources()::addLast);

                }

            } catch (IOException e) {

                throw new IllegalStateException("加载配置文件失败: " + location, e);

            }

        }

        

        private void loadYamlResourceOptional(ConfigurableEnvironment environment, String location) {

            try {

                Resource resource = new ClassPathResource(location.replace("classpath:", ""));

                if (resource.exists()) {

                    List> sources = loader.load(location, resource);

                    sources.forEach(environment.getPropertySources()::addLast);

                }

            } catch (IOException e) {

                // 可选配置,忽略错误

            }

        }

        

        private void validateConfiguration(ConfigurableEnvironment environment) {

            // 配置验证逻辑

            String requiredProperty = environment.getProperty("app.required.property");

            if (requiredProperty == null) {

                throw new IllegalStateException("缺少必需的配置属性: app.required.property");

            }

        }

    }

    

    // Profile激活策略配置

    @Bean

    @Profile("dev")

    public DataSource devDataSource() {

        // 开发环境数据源

        HikariDataSource dataSource = new HikariDataSource();

        dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/dev");

        dataSource.setUsername("dev_user");

        dataSource.setPassword("dev_password");

        dataSource.setMaximumPoolSize(10);

        return dataSource;

    }

    

    @Bean

    @Profile("prod")

    public DataSource prodDataSource() {

        // 生产环境数据源

        HikariDataSource dataSource = new HikariDataSource();

        dataSource.setJdbcUrl("jdbc:mysql://prod-cluster:3306/prod");

        dataSource.setUsername(System.getenv("DB_USERNAME"));

        dataSource.setPassword(System.getenv("DB_PASSWORD"));

        dataSource.setMaximumPoolSize(50);

        return dataSource;

    }

    

    // 条件配置示例

    @Configuration

    @ConditionalOnProperty(name = "app.features.enable-cache", havingValue = "true")

    @ConditionalOnClass(RedisConnectionFactory.class)

    public static class CacheConfiguration {

        

        @Bean

        @Profile({"dev", "test"})

        public CacheManager simpleCacheManager() {

            return new ConcurrentMapCacheManager("products", "categories");

        }

        

        @Bean

        @Profile({"staging", "prod"})

        public CacheManager redisCacheManager(RedisConnectionFactory connectionFactory) {

            RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()

                .entryTtl(Duration.ofMinutes(10))

                .serializeValuesWith(RedisSerializationContext.SerializationPair

                    .fromSerializer(RedisSerializer.json()));

            

            return RedisCacheManager.builder(connectionFactory)

                .cacheDefaults(config)

                .build();

        }

    }

}


// 应用启动类

@SpringBootApplication

public class ProductServiceApplication {

    

    public static void main(String[] args) {

        SpringApplication app = new SpringApplication(ProductServiceApplication.class);

        

        // 设置默认Profile

        app.setDefaultProperties(Collections.singletonMap(

            "spring.profiles.default", "dev"

        ));

        

        // 启动应用

        app.run(args);

    }

    

    // Profile激活监听器

    @EventListener

    public void handleApplicationStarted(ApplicationStartedEvent event) {

        ConfigurableEnvironment env = event.getApplicationContext().getEnvironment();

        String[] activeProfiles = env.getActiveProfiles();

        

        log.info("激活的Profiles: {}", Arrays.toString(activeProfiles));

        log.info("当前环境: {}", env.getProperty("app.environment"));

        log.info("应用名称: {}", env.getProperty("spring.application.name"));

        

        // 根据Profile执行初始化逻辑

        if (Arrays.asList(activeProfiles).contains("dev")) {

            initializeDevelopmentEnvironment();

        } else if (Arrays.asList(activeProfiles).contains("prod")) {

            initializeProductionEnvironment();

        }

    }

    

    private void initializeDevelopmentEnvironment() {

        log.info("初始化开发环境...");

        // 开发环境特定的初始化逻辑

    }

    

    private void initializeProductionEnvironment() {

        log.info("初始化生产环境...");

        // 生产环境特定的初始化逻辑

    }

}

```


## 部署与运行配置


```bash

#!/bin/bash

# deploy.sh - 多环境部署脚本


# 环境变量配置

ENVIRONMENT=${ENVIRONMENT:-dev}

CONFIG_DIR="/app/config"

LOG_DIR="/app/logs"


# 根据环境选择配置

case $ENVIRONMENT in

    "dev")

        PROFILE="dev"

        JAVA_OPTS="-Xmx512m -Xms256m"

        ;;

    "test")

        PROFILE="test"

        JAVA_OPTS="-Xmx1g -Xms512m"

        ;;

    "staging")

        PROFILE="staging"

        JAVA_OPTS="-Xmx2g -Xms1g"

        ;;

    "prod")

        PROFILE="prod"

        JAVA_OPTS="-Xmx4g -Xms2g -XX:+UseG1GC -XX:MaxGCPauseMillis=200"

        ;;

    *)

        echo "未知环境: $ENVIRONMENT"

        exit 1

        ;;

esac


# 创建目录

mkdir -p $CONFIG_DIR $LOG_DIR


# 复制配置文件

cp /app/resources/application-$PROFILE.yml $CONFIG_DIR/application.yml


# 导出环境变量

export SPRING_PROFILES_ACTIVE=$PROFILE

export SPRING_CONFIG_LOCATION=$CONFIG_DIR/

export LOGGING_FILE_NAME=$LOG_DIR/app.log

export JAVA_OPTS


# 启动应用

java $JAVA_OPTS \

    -Dspring.profiles.active=$PROFILE \

    -Dspring.config.location=$CONFIG_DIR/ \

    -Dlogging.file.name=$LOG_DIR/app.log \

    -jar /app/product-service.jar

```


```dockerfile

# Dockerfile多环境构建

FROM openjdk:17-jdk-slim as builder


# 构建阶段

WORKDIR /app

COPY . .

RUN ./gradlew clean bootJar


FROM openjdk:17-jre-slim


# 运行时环境变量

ARG ENVIRONMENT=dev

ENV SPRING_PROFILES_ACTIVE=${ENVIRONMENT}

ENV JAVA_OPTS="-XX:+UseContainerSupport -XX:MaxRAMPercentage=75.0"


# 创建非root用户

RUN groupadd -r spring && useradd -r -g spring spring

USER spring:spring


WORKDIR /app

COPY --from=builder /app/build/libs/*.jar app.jar


# 配置文件目录

VOLUME /app/config

VOLUME /app/logs


# 健康检查

HEALTHCHECK --interval=30s --timeout=3s --start-period=60s --retries=3 \

    CMD curl -f http://localhost:8080/actuator/health || exit 1


# 启动命令

ENTRYPOINT ["sh", "-c", "java $JAVA_OPTS -Dspring.profiles.active=$SPRING_PROFILES_ACTIVE -jar app.jar"]

```


基于Spring Boot Profile的多环境配置机制,为企业应用提供了灵活、安全的配置管理方案。通过分级配置、条件装配和环境隔离,实现了从开发到生产的全生命周期配置管理。在实际应用中,需要结合配置中心、密钥管理和持续部署工具,构建完整的配置管理体系,确保应用在不同环境中的一致性和安全性。


请使用浏览器的分享功能分享到微信等