针对常见应用场景,可以分为以下几个方面来考虑
注意:本文只针对没有接入统一配置中心、配置平台的情况
一、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坐标如下:
配置好后就可以直接使用了,例如,在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