本文转自: http://yhjhappy234.blog.163.com/blog/static/3163283220119201111149/
最近项目采用SCM统一管理的方式,通过hudson自由打包给测试和IDC运维人员,但是存在一个问题,就是我们的配置文件一直是存在于classpath下面的,而当程序包(hudson通过Maven自动打出war包)打给测试和IDC人员后,他们需要做一个很繁琐的事情就是需要把war包解开,然后将对应的配置文件改为测试或者IDC上端的配置文件,然后再拷贝文件到对应的环境进行发布,显然很麻烦,并且这些都需要人为去做,而现在web做集群又是通用提升性能的方式,显然为我们的程序升级发布和检测正确性带来了不少的麻烦,曾经有一次IDC有一台机器的配置文件因忘记替换,而导致IDC的机器通过VPN自动连接到内网将大批数据写入了测试数据库中,为此我们损失了近十万的用户数据,这是一件很危险的事情,当然最好的方法就是我们发布的war包直接拷贝到对应的目录就可以使用了!
为了达到这个目标,我们有很多途径可以走!
u 方案一:不更改程序,使用替换法适配对应的配置文件爱你。IDC上端有一台专门的适配器,当一个war包发布后先通过这台机器,这台机器自动解开对应的war包,然后将IDC上端的配置文件拷贝到对应的classpath下面,然后将新的文件重新打成一个war包。然后剩余所有的机器都通过同步的方式从这个适配机上取最新的war包程序,这样可以确保只要适配机的数据是正确的,则所有的机器所取到的程序包都是正确的。当然要确保适配机的程序是正确的,需要在适配机执行完毕适配之后做一次验证,当然,适配机器只能在内网访问,当验证通过之后,其他机器就可以通过更新的方式从适配机取最新的程序包,而这一切都可以通过shell脚本轻松自动化完成。
u 方案二:通过配置环境变量实现配置文件与程序包分离,如程序包放在对应的root目录下,而配置文件放在conf目录下,每次更新程序只要更新root目录下的war程序即可,而无需做替换配置文件等风险性操作!
方案对比:< xmlnamespace prefix ="o" ns ="urn:schemas-microsoft-com:office:office" />
? 方案一缺陷:对适配机的要求颇高,一旦适配机打出的war包不正确,则所有的机器没有一台是正确的,并且当数据库结构发生变更的时候,适配机因为和其他机器一样访问上端IDC的DB阵列,因此不能单独验证,需要DB升级完成之后统一验证,这样反而增大了升级的风险。
? 方案二缺陷:当配置文件发生变更的话,需要所以的机器做统一升级(当然这个因为结构目录统一,可以通过shell脚本快速搞定),为配置文件带来了一定的风险。当新增集群机器的时候,需要配置对应的环境变量,如果没配置会导致对应的程序无法启动(程序无法启动是很容易发现的,并且IDC环境一般都是通过虚拟化的方式clone新的机器,clone的机器一般已经设置好了环境变量,即使没设置,通过shell脚本也能很快的统一设置)。
通过对比,我们发现方案二优势稍大一点(虽然我们现在的IDC已经使用第一种方案),因此经过我们协商,下个版本采用方案二的方式执行。
方案已经确定,那我们该怎么配置实现分离呢?
显然Linux为我们提供了很多途径来设置环境变量,但是很显然,我们的程序属于应用程序,如果直接在系统环境变量中设置显然是不好的,因此我们采用了在tomcat上来设置环境变量。
u 方式一:通过IDE工具的启动参数设置
1、 打开我们的IDE工具
2、 点击菜单栏“window”->“perserences” ->“tomcat” ->“JVM setting”,如下图所示< xmlnamespace prefix ="v" ns ="urn:schemas-microsoft-com:vml" />
在这里add你要的环境变量即可,如“CONF_HOME=d:/conf”
u 方式二:通过修改启动脚本来设置
1、 打开tomcat的安装目录
2、 进入对应的bin目录
3、 找到对应的文件然后做如下修改
a) Linux机器:找到catalina.sh文件,
加入代码:JAVA_OPTS="-$your env$=$your value$"
如:JAVA_OPTS="-CONF_HOME=/app/conf –LOGS_HOME=/app/logs"
b) Windows机器:找到catalina.bat文件
加入代码:JAVA_OPTS="-$your env$=$your value$"
如:JAVA_OPTS="-CONF_HOME=d:/conf –LOGS_HOME=d:/logs"
如此以来,我们的环境变量就配好了,下面的操作就是修改程序代码了,找到我们的配置文件,全部使用环境变量代替就好了,如Spring的配置文件,我们就可以这么配置
<property name="locations">
<list>
<value>file:${PASSPORT_KEDOU_CONFIG_HOME}/server.properties</value>
<value>file:${PASSPORT_KEDOU_CONFIG_HOME}/sms.properties</value>
<value>file:${PASSPORT_KEDOU_CONFIG_HOME}/baseStoneDb.properties</value>
<value>file:${PASSPORT_KEDOU_CONFIG_HOME}/cache.properties</value>
<value>file:${PASSPORT_KEDOU_CONFIG_HOME}/email.properties</value>
</list>
</property>
我们的日志文件
log4j也可以这么配置了
log4j.appender.errorLog=org.apache.log4j.DailyRollingFileAppender
log4j.appender.errorLog.File=${PASSPORT_KEDOU_LOG_HOME}/payment.log
log4j.appender.errorLog.MaxBackupIndex=365
log4j.appender.errorLog.layout=org.apache.log4j.PatternLayout
log4j.appender.errorLog.layout.ConversionPattern=%d%p%m%n
log4j.logger.com.shunwang.baseStone.memberSub.exception.MemberSubExp=info,errorLog
log4j.appender.sqlLog=org.apache.log4j.DailyRollingFileAppender
log4j.appender.sqlLog.File=${PASSPORT_KEDOU_LOG_HOME}/sqlLog.log
log4j.appender.sqlLog.MaxBackupIndex=365
log4j.appender.sqlLog.layout=org.apache.log4j.PatternLayout
log4j.appender.sqlLog.layout.ConversionPattern=%d%p%m%n
log4j.logger.java.sql=debug,sqlLog
log4j.rootLogger=info,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
# Pattern to output the caller's file name and line number.
log4j.appender.stdout.layout.ConversionPattern=%p[%t]%C{1}.%M(%L)|%m%n
log4j.appender.filterLog=org.apache.log4j.DailyRollingFileAppender
log4j.appender.filterLog.File=${PASSPORT_KEDOU_LOG_HOME}/filter.log
log4j.appender.filterLog.MaxBackupIndex=365
log4j.appender.filterLog.layout=org.apache.log4j.PatternLayout
log4j.appender.filterLog.layout.ConversionPattern=%d%p%m%n
log4j.logger.com.shunwang.basepassport.filter.InterfaceLogFilter=error,filterLog
log4j.appender.exceptionLog=org.apache.log4j.DailyRollingFileAppender
log4j.appender.exceptionLog.File=${PASSPORT_KEDOU_LOG_HOME}/exceptionLog.log
log4j.appender.exceptionLog.MaxBackupIndex=365
log4j.appender.exceptionLog.layout=org.apache.log4j.PatternLayout
log4j.appender.exceptionLog.layout.ConversionPattern=%d%p%m%n
log4j.logger.com.shunwang.passport.common.interceptor.ExceptionInterceptor=error,exceptionLog
如此一来,我们实现了配置文件和程序包的分离,还省去了
log4j各个平台之间切换需要更改配置文件路径(Linux和windows路径不兼容)不兼容的问题了,是不是很方便呢?