在项目中使用一些比较新的库总会给你带来很多快乐,在这篇文章中,我将会给你介绍一个在Java中读取配置文件的框架——Apache Commons Configuration framework.
你会了解到
·从XML文件中获取数据
·访问环境变量
·连接不同类型的配置信息(基于XML的,基于环境变量的,等等)
·在程序改变后自动重新加载配置。
在我们的示例中将会使用XML文件和环境变量的两种方式存储一个数据库的配置信息(开发、测试、产品,等等)。接下来你将会看到具体的内容,但是首先先配置一下Maven。
Maven设置
我们的示例程序需要在pom.xml文件中添加如下依赖:
<dependencies>
<dependency>
<groupId>commons-configuration</groupId>
<artifactId>commons-configuration</artifactId>
<version>1.8</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.8.0</version>
</dependency>
<dependency>
<groupId>commons-jxpath</groupId>
<artifactId>commons-jxpath</artifactId>
<version>1.3</version>
</dependency>
</dependencies>
简单的数据库配置
设想我们有一个简单的数据库配置信息存储在XML文件中:
<?xmlversion="1.0"encoding="UTF-8"?>
<!-- const.xml -->
<config>
<database>
<url>127.0.0.1</url>
<port>1521</port>
<login>admin</login>
<password>pass</password>
</database>
</config>
为了拿到url和port我们用如下的代码:
XMLConfiguration config =new XMLConfiguration("const.xml");
// 127.0.0.1
config.getString("database.url");
// 1521
config.getString("database.port");
XMLConfiguration是一个Apache Commons类,他可以从指定的配置文件中加载内容,并且提供一个很好的以指定的点的方式得到存储的值。例如例子中的表达式database.port映射到xml文件中的 config/database/port节点的值“1521”。当然还有很多方式获取数据。这里有一些基本的用法:
getBoolean
getByte
getDouble
getFloat
getInt
getInteger
getList
getLong
getStringArray
你可通过查看Apache Commons的JavaDoc查看更多的使用方式。
将如上配置扩展一步
设想,过了一会我们想配置多个数据库,我们可以在配置文件中这样写:
<?xmlversion="1.0"encoding="UTF-8"?>
<!-- const.xml -->
<config>
<databases>
<database>
<name>dev</name>
<url>127.0.0.1</url>
<port>1521</port>
<login>admin</login>
<password>pass</password>
</database>
<database>
<name>production</name>
<url>192.23.44.100</url>
<port>1521</port>
<login>admin</login>
<password>not-so-easy-pass</password>
</database>
</databases>
</config>
现在我们要访问url数据我们可以这样:
XMLConfiguration config =new XMLConfiguration("const.xml"); // 127.0.0.1
config.getString("databases.database(0).url"); // 192.23.44.100
config.getString("databases.database(1).url");
你可以看到这次多了参数,0代表第一个,1代表第二个。
XPath表达式
定点的访问方式没问题,但是只是在一些简单的情况下,对于复杂的真实的状况来讲,我们可能需要使用XPath表达式语言。这里的主要优点是,即便你使用了XML的高级查询,程序看起来仍然比较简洁易懂。
XMLConfiguration config =new XMLConfiguration("const.xml");
config.setExpressionEngine(new XPathExpressionEngine()); // 127.0.0.1
config.getString("databases/database[name = 'dev']/url"); // 192.23.44.100
config.getString("databases/database[name = 'production']/url");
这里是上面两个XPath表达式查询的一个解释:
访问环境变量
在Apache Commons Configuration的帮助下你可以轻松的访问到系统的环境变量。下面是访问系统中ENV_TYPE变量的方法:
EnvironmentConfiguration config =new EnvironmentConfiguration();
config.getString("ENV_TYPE");
假设变量ENV_TYPE已经设置好了,想看上面的程序是否运行正确,你可以在控制台运行如下脚本:
echo %ENV_TYPE% # for Windows
# or...
echo $ENV_TYPE # for Linux/Mac OS
你将会看到ENV_TYPE的值。
联合配置
让我们总结一下我们了解的东西,下面的getDbUrl方法做如下事情:
·检查系统环境变量中叫做ENV_TYPE的值。
·如果值是dev或者produtcion就返回相应的数据库url
·如果变量没有配置就抛出异常。
public String getDbUrl() throws ConfigurationException {
EnvironmentConfiguration envConfig =new EnvironmentConfiguration();
String env = envConfig.getString("ENV_TYPE");
if("dev".equals(env) ||"production".equals(env)) {
XMLConfiguration xmlConfig =new XMLConfiguration("const.xml");
xmlConfig.setExpressionEngine(new XPathExpressionEngine());
String xpath ="databases/database[name = '"+ env +"']/url";
return xmlConfig.getString(xpath);
}else{
String msg ="ENV_TYPE environment variable is "+
"not properly set";
throw new IllegalStateException(msg);
}
}
集中你的配置
对每个不同的需要配置的对象创建多个配置比较烦。假如我们想添加其他的基于XML的配置,我们会怎么搞?我们需要创建另一个XMLConfiguration对象,这会给管理带来很多麻烦。一个解决办法是把配置文件信息集中到一个单个XML文件中。下面是一个例子:
<?xmlversion="1.0"encoding="UTF-8"?>
<!-- config.xml -->
<configuration>
<env/>
<xmlfileName="const.xml"/>
</configuration>
你需要使用DefaultConfigurationBuilder类,最终版本的getDbUrl方法看起来像这样:
public String getDbUrl()throws ConfigurationException {
DefaultConfigurationBuilder builder =
new DefaultConfigurationBuilder("config.xml");
boolean load =true;
CombinedConfiguration config = builder.getConfiguration(load);
config.setExpressionEngine(new XPathExpressionEngine());
String env = config.getString("ENV_TYPE");
if("dev".equals(env) ||"production".equals(env)) {
String xpath ="databases/database[name = '"+ env +"']/url";
return config.getString(xpath);
}else{
String msg ="ENV_TYPE environment variable is "+
"not properly set";
throw new IllegalStateException(msg);
}
}
自动重新加载
Apache Commons Configuration有很多非常酷的特性。其中一个就是当基于文件的配置变化的时候自动加载,因为我们可以设置加载策略。框架会轮询配置文件,当文件的内容发生改变时,配置对象也会刷新。你可以用程序控制:
XMLConfiguration config =new XMLConfiguration("const.xml");
ReloadingStrategy strategy =new FileChangedReloadingStrategy();
strategy.setRefreshDelay(5000);
config.setReloadingStrategy(strategy);
或者把他写到主配置文件中:
<?xmlversion="1.0"encoding="UTF-8"?>
<!-- config.xml -->
<configuration>
<env/>
<xmlfileName="const.xml">
<reloadingStrategyrefreshDelay="5000"
config-class="org.apache.commons.configuration.reloading.FileChangedReloadingStrategy"/>
</xml>
</configuration>
每五秒框架都检查一下配置文件有没有改变。
最后
我个人用来管理需要配置的代码的时候的选择是使用Apache Commons。我希望这篇文章可以让你相信这个框架可以提供一个非常有用的接口用来访问你的静态数据。最后需要说的一点,这篇文章的内容只是这个框架的功能的一部分。此框架一些其他的有趣的功能是:
·从不同的数据源装载配置信息,例如properties文件、ini文件、数据库等等。
·给配置对象增加新的属性,并把它回存到文件中。
·监听配置对象改变的事件。(这点可以让你在配置发生改变的时候及时作出处理)
·自动解析配置文件的实际路径(不管你是把它放在程序文件夹下还是一个jar中。)