项目多环境配置管理方案


针对常见应用场景,可以分为以下几个方面来考虑

注意:本文只针对没有接入统一配置中心、配置平台的情况


一、Java服务器端项目


1、对于项目的框架或者组件,如果支持编程方式配置,则编程根据不同环境读取不同配置,例如Spring框架、Logback日志库都支持;

    1)  如果使用Spring Boot,直接采用官方推荐的配置切换方式:设置spring.profiles.active,可以是jvm变量、main启动参数、环境变量等(建议使用jvm变量);

    2)  如果使用Spring框架(但是非Spring Boot),环境相关的配置参数放在properties文件中,写个工具类,就可以根据不同环境(建议根据jvm变量识别)读取对应properties;

    3)  如果使用 logback,在非Spring Boot环境下,可以把配置参数放在properties文件中,根据不同环境(建议根据jvm变量识别)读取对应properties;在Spring Boot环境下,可以使用logback的springProperty标签获取spring托管的参数;


2、其他组件,如果不支持编程,(比如某些环境要引入一些特殊的二进制包,脚本,图片,或者xml文件等),则采用maven打包时输入-P参数选择打包指定文件达到目的。


二、客户端(Android、iOS、H5等)项目


1. 利用打包工具,在打包时自动区分各环境的配置文件。(无需人工手动替换)



下面就以上提到的某些方面进行说明


1、JVM变量、环境变量的配置

    IDE工具:

        可以直接在图形化的配置窗口(VM arguments 或 VM options)配置 

    IDEA配置JVM启动参数 参见: http://blog.csdn.net/wangnayu/article/details/76794112

    Eclipse配置JVM启动参数 参见:https://jingyan.baidu.com/article/624e7459653ca534e8ba5a26.html


    服务器JVM启动参数:

      一般是在启动脚本或者配置脚本里面添加。 

    TOMCAT JVM启动参数配置 :在catalina.bat或catalina.sh里面设置,参见: http://blog.csdn.net/xinluke/article/details/51490048


    系统环境变量设置:

    1)Windows,参见:https://jingyan.baidu.com/article/d5a880eb6aca7213f047cc6c.html

    2)Linux,有多种方式,参见:http://www.cnblogs.com/answercard/p/7142448.html    


2、Maven打包切换配置的方法(适用于Log4j 等组件的配置)

    如果组件自身不支持以编程的方式进行配置,则可以借助打包工具,maven、gradle等,下面以maven为例说明。用法参见:https://my.oschina.net/u/2341924/blog/667730


3、Spring 的配置方法

在Spring 非 Spring Boot环境下,方案如下:

(1) 尽量将配置都交给Spring管理(可以通过注入bean方式或者@Value等方式获取配置的值);

(2) 将Spring的配置参数,都集中在一个或者多个properties文件中,并将环境相关的配置 分环境单独放置在后缀为"-dev"、"-test"、"-prod"...的properties文件中;


配置切换方式一:

利用Spring的spring.profiles.active参数来配置,例如:

<beans profile="dev">  
    <!-- 开发环境 -->
    <context:property-placeholder location="classpath:jdbc-dev.properties,classpath:conf.properties"/> 
</beans>
<beans profile="sit">
    <!-- 测试sit环境 -->
    <context:property-placeholder location="classpath:jdbc-sit.properties,classpath:conf.properties"/> 
</beans>
<beans profile="uat">
    <!-- 测试uat环境 -->
    <context:property-placeholder location="classpath:jdbc-uat.properties,classpath:conf.properties"/> 
</beans>
<beans profile="pre">
    <!-- 预发布环境 -->
    <context:property-placeholder location="classpath:jdbc-pre.properties,classpath:conf.properties"/> 
</beans>
<beans profile="prod">
    <!-- 生产环境 -->
    <context:property-placeholder location="file:${java.home}/jdbc-prod.properties,classpath:conf.properties"/> 
</beans>


配置方式二:(推荐)

扩展spring的properties加载类org.springframework.beans.factory.config.PropertyPlaceholderConfigurer,使其能够根据不同的环境读取不同的properties配置文件,关于这个小工具,已经写好了,只需要在项目中引入即可,maven坐标如下:

<!-- 用法参见http://10.2.10.22/zollty/zollty-commons/tree/master/zollty-common-util -->
<dependency>
  <groupId>com.zollty.commons</groupId>
  <artifactId>zollty-common-util</artifactId>
  <version>最新版本</version>
</dependency>

配置好后就可以直接使用了,例如,在Spring的xml配置文件中可以像下面这么配置:

<bean id="confProperties" class="io.zollty.util.EnvirmentPropertyConfigurer">
<property name="globalLocations">
  <list> <!-- 全局配置 -->
    <value>classpath:conf.properties</value>
    <value>classpath:dubbo/consumer.properties</value>
  </list>
</property>
<!-- 分为 dev sit uat pre prod等环境 -->
<property name="environmentLocations">
  <map> <!-- 环境相关配置,文件后缀'.properties'省略,'classpath:'也可以省略 -->
    <entry key="dev" value="classpath:conf-dev" />
    <entry key="sit" value="classpath:conf-sit,file:C:/Users/consumer"/>
    <entry key="uat" value="file:${java.home}/conf-uat"/>
    <entry key="pre" value="file:${java.home}/conf-pre"/>
    <entry key="prod" value="file:${java.home}/conf-prod"/>
    <!-- dev为默认配置。切换其他配置,需要设置参数,例如JVM参数 -Dspring.profiles.active=test -->
    <!-- 支持多个文件逗号分隔 -->
    <!-- 支持系统\环境变量占位符 -->
    <!-- 支持'file:'前缀从文件系统读取文件 -->
  </map>
</property>
<!-- 这个配置是可选的,设置为true代表 找不到配置时 不报错(默认为null),否则会报错提示 -->
<property name="ignoreUnresolvablePlaceholders" value="false"/>
</bean>

使用时,可以在classpath下面放置如下一些配置文件:

    conf.properties(全局配置)

    conf-dev.properties(开发环境的配置)

    conf-sit.properties(测试环境SIT的配置)

    conf-uat.properties(测试环境UAT的配置)

    conf-prod.properties(生产环境的配置)

    conf-demoxxx.properties(其他分类配置)

    dubbo/consumer.properties(其他分类配置)

这个工具默认会读取全局配置,环境默认读取dev下面的配置,如果想切换到测试环境的配置,可以配置JVM系统变量:

    -Dspring.profiles.active=test

或者操作系统的环境变量也可以。

这样配置的话,生效的就是 test 环境对应的配置。


4、Logback的配置方法

    logback也支持多种方式扩展,一种是在logback.xml配置中使用条件表达式判断,第二种方法是使用statusListener,在logback配置解析之前调用一个自定义的类来设置参数。

    下面给出配置示例:

<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false">
  
  <!-- 这个工具类参见:http://10.2.10.22/zollty/zollty-commons/tree/master/zollty-common-util -->  
  <statusListener class="io.zollty.util.InitLogConfigListener" />
  
  <!-- 部署的环境类型:dev、test、product -->
  <property name="DEPLOY_ENV" value="${deploy.env:-dev}" />
  
  <!-- 日志路径,这里是相对路径,web项目eclipse下会输出到当前目录./logs/下,如果部署到linux上的tomcat下,会输出到tomcat/logs/目录 下 -->
  <property name="LOG_HOME" value="${catalina.base:-.}/logs" />
    
  <!-- 日志文件大小,超过这个大小将被压缩 -->
  <property name="LOG_MAX_SIZE" value="100MB" />
  <!-- 日志输出格式 -->
  <property name="LOG_COMMON_PATTERN" value="%d{HH:mm:ss.SSS} [%thread] [%level] %logger - %msg%n" />
  <property name="LOG_DEV_PATTERN" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{48}:%line - %msg%n" />
  
  <!-- 主日志级别 -->
  <property name="ROOT_LEVEL" value="${log.root.level:-DEBUG}" />
  
  <!-- APP 日志级别 -->
  <property name="APP_LEVEL" value="${log.app.level:-TRACE}" />
  <!-- APP Package 前缀: cn.zollty.lightning -->
  <property name="APP_PACKAGE" value="cn.zollty.lightning" />
    
  <include resource="includedConfig.xml"/>
    
  <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
    <encoder>
      <pattern>${LOG_DEV_PATTERN}</pattern>
    </encoder>
  </appender>
    
  <appender name="FILTER-DATA" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <file>${LOG_HOME}/filter.log</file>
    <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
      <fileNamePattern>${LOG_HOME}/filter/filter-%d{yyyy-MM-dd}-%i.log.zip</fileNamePattern>
      <maxHistory>90</maxHistory>
      <TimeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
        <MaxFileSize>100MB</MaxFileSize>
      </TimeBasedFileNamingAndTriggeringPolicy>
    </rollingPolicy>
    <encoder>
      <pattern>${LOG_COMMON_PATTERN}</pattern>
    </encoder>
  </appender>
    
  <appender name="ASYNC1" class="ch.qos.logback.classic.AsyncAppender">
    <appender-ref ref="FILTER-DATA" />
  </appender>
    
  <include resource="special_log_level.xml"/>
  
  <logger name="${APP_PACKAGE}" level="${APP_LEVEL}" />
    
  <logger name="FILTER-LOGGER" level="${APP_LEVEL}" additivity="false">
    <appender-ref ref="ASYNC1" />
  </logger>
  
  <root level="${ROOT_LEVEL}">
    <!-- Required: exception log -->
    <appender-ref ref="FILE_EXCEPTION"/>
    <!-- Required: app log  -->
    <appender-ref ref="FILE_APP"/>
      
    <!-- Optional: show all debug or trace info -->
    <!-- <appender-ref ref="FILE_DEBUG"/> -->
    <!-- <appender-ref ref="FILE_TRACE"/> -->
      
    <if condition='p("DEPLOY_ENV").contains("dev")'>
      <then>
        <appender-ref ref="STDOUT" />
      </then>
    </if>
      
  </root>
  
</configuration>


这个配置的关键之处在于系统变量、环境变量条件表达式的使用:

1、

  <!-- 部署的环境类型deploy.env = dev、test、product -->

  <property name="DEPLOY_ENV" value="${deploy.env:-dev}" />

2、

  <!-- 主日志级别 -->

  <property name="ROOT_LEVEL" value="${log.root.level:-DEBUG}" />

  <!-- APP 日志级别 -->

  <property name="APP_LEVEL" value="${log.app.level:-TRACE}" />

3、

<if condition='p("DEPLOY_ENV").contains("dev")'>

  <then>

    <appender-ref ref="STDOUT" />

  </then>

</if>


5、编程方式自动读取配置(以Logback为例)

    上面说到,有一些组件是支持以编程方式来配置的,logback就支持,方法是在logback.xml配置如下标签:

<statusListener class="io.zollty.util.InitLogConfigListener" />

在这个类InitLogConfigListener中,就可以任意发挥了,例如可以从jvm变量中获取值。这个工具类参见:

http://10.2.10.22/zollty/zollty-commons/tree/master/zollty-common-util



© 2009-2020 Zollty.com 版权所有。渝ICP备20008982号