web项目部署中存在的配置文件问题:java
web项目以war包的形式,部署在tomcat中,同时项目须要访问一些其余的东东,例如访问数据库,调用别的项目的API。在开发中,这些须要访问的外部地址一般以配置文件的形式存在于项目中。以下图:web
在更换项目的部署环境后,或者调用的外部应用地址发生变化,就须要更改配置文件。spring
最直接的问题:数据库
发布了一个测试包,放在测试环境上,测试经过以后,要将测试包发布到生产环境中,此时测试环境与生产环境的各类配置的地址是不一样的,解决方案有两种apache
(1)将配置文件修改成生产环境的配置,从新打包。tomcat
(2)将测试环境的包,升级到生产环境后,修改配置文件为生产环境的配置文件。app
无论是哪一种方式都是存在风险的。对于(1)来讲升级到生产环境的包并非测试经过的包;对于(2)来讲增长了人工成本和出错几率。spring-boot
解决方案:测试
若是配置文件中,须要变化的地址使用变量的形式,项目在被部署到不一样的环境中后,读取各自环境中的变量,是否是就能够解决这个问题了呢。ui
步骤:
(1)在环境变量中增长一个参数配置,tomcat启动后或者项目启动后能够加载改参数
(2)将项目中的配置文件修改为已经定义的变量
(3)项目的代码部分在加载配置文件的时候,能够自动替换掉变量
具体实现:
(1)修改tomcat的Catalina.sh文件
在cygwin=false上面增长JAVA_OPTS="-DbaseDomain=xxxxxx"
设置了变量以后,在java的项目中可使用System.getProperty("baseDomain")来获取。
(2)修改项目的配置文件,须要修改的内容使用${baseDomain}替换。
(3)项目中解析${baseDomain}
配置完成以后,便可初步实现build once,run any enviroment了。
--------------
附上解析配置文件中${baseDomain}的代码
import java.util.Properties; import org.apache.log4j.helpers.LogLog; public class OptionConverterUtil { static String DELIM_START = "${"; static char DELIM_STOP = '}'; static int DELIM_START_LEN = 2; static int DELIM_STOP_LEN = 1; public static String substVars(String val, Properties props) throws IllegalArgumentException { StringBuffer sbuf = new StringBuffer(); int i = 0; int j, k; while(true) { j=val.indexOf(DELIM_START, i); if(j == -1) { // no more variables if(i==0) { // this is a simple string return val; } else { // add the tail string which contails no variables and return the result. sbuf.append(val.substring(i, val.length())); return sbuf.toString(); } } else { sbuf.append(val.substring(i, j)); k = val.indexOf(DELIM_STOP, j); if(k == -1) { throw new IllegalArgumentException('"'+val+ "\" has no closing brace. Opening brace at position " + j + '.'); } else { j += DELIM_START_LEN; String key = val.substring(j, k); // first try in System properties String replacement = getSystemProperty(key, null); // then try props parameter if(replacement == null && props != null) { replacement = props.getProperty(key); } if(replacement != null) { // Do variable substitution on the replacement string // such that we can solve "Hello ${x2}" as "Hello p1" // the where the properties are // x1=p1 // x2=${x1} String recursiveReplacement = substVars(replacement, props); sbuf.append(recursiveReplacement); } i = k + DELIM_STOP_LEN; } } } } public static String getSystemProperty(String key, String def) { try { return System.getProperty(key, def); } catch(Throwable e) { // MS-Java throws com.ms.security.SecurityExceptionEx LogLog.debug("Was not allowed to read system property \""+key+"\"."); return def; } } }
在第三步配置文件参数解析操做过程当中参考了log日志的作法,解析方法也是从log4j的源代码中copy出来的。
---------------
看了一下spring-boot,若是使用spring-boot,则不须要上述设置,直接配置不一样的配置文件。spring-boot会根据不一样的环境加载不一样的配置文件,原理感受和上述相似。