commons-configuration是apache为java应用程序提供的一个通用的配置文件管理接口,可以支持多种配置文件格式:
Properties files
XML documents
Windows INI files
Property list files (plist)
JNDI
JDBC Datasource
System properties
Applet parameters
Servlet parameters
commons-configuration2是在已经广泛使用的commons-configuration 1.x版本基础上的一个升级版本,与1.x版本并不保持兼容。
刚开始使用commons-configuration2
,这里做为笔记记录学习过程中的要点。
pom.xml 依赖配置如下,commons-beanutils,commons-jxpath
对于commons-configuration2
都是optional可选配件,但在本例都要用到所以必须加上否则运行会抛出异常 java.lang.ClassNotFoundException
:
<dependency>
<groupId>org.apache.commonsgroupId>
<artifactId>commons-configuration2artifactId>
<version>2.1.1version>
dependency>
<dependency>
<groupId>commons-beanutilsgroupId>
<artifactId>commons-beanutilsartifactId>
<version>1.9.3version>
dependency>
<dependency>
<groupId>commons-jxpathgroupId>
<artifactId>commons-jxpathartifactId>
<version>1.3version>
dependency>
相比properties文件格式 xml要复杂多了(每个节点都可以有attribute),所以对于xml格式的配置文件,访问一个元素的值或attribute需要一套表达式规则来规定。比如路径节点用.
分隔,attribute用@
开头。commons-configuration提供了默认规则,但这个规则用户也是可以自定义的,也可以使用xpath标准。
下面的代码演示如何使用默认规则、xpath、自定义规则来访问Xml配置文件中的节点.
先贴出演示用的xml文件。
token.xml,放在源码根目录下,是一个很简单的配置文件,其中的description
是节点属性。
<configuration>
<token>
<device>
<validate>truevalidate>
device>
<person>
<validate>truevalidate>
<expire description="人员令牌失效时间(分钟) ">60expire>
person>
token>
configuration>
ConfigTest2.java
package net.gdface.facelog;
import org.apache.commons.configuration2.XMLConfiguration;
import org.apache.commons.configuration2.builder.fluent.Configurations;
import org.apache.commons.configuration2.tree.DefaultExpressionEngine;
import org.apache.commons.configuration2.tree.DefaultExpressionEngineSymbols;
import org.apache.commons.configuration2.tree.xpath.XPathExpressionEngine;
import org.junit.Test;
public class ConfigTest2 {
@Test
public void test2() {
try {
Configurations configs = new Configurations();
XMLConfiguration config = configs.xml(this.getClass().getClassLoader().getResource("token.xml"));
{
// 使用默认的符号定义创建一个表达式引擎
DefaultExpressionEngine engine = new DefaultExpressionEngine(
DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS);
// 指定表达式引擎
config.setExpressionEngine(engine);
System.out.println(config.getBoolean("token.device.validate"));
System.out.println(config.getInt("token.person.expire"));
System.out.println(config.getString("token.person.expire[@description]"));
}
{
// 使用 XPath表达式引擎
// 请注意这里路径分隔符和attribute标签与上面使用DefaultExpressionEngine是不同的
XPathExpressionEngine xpathEngine = new XPathExpressionEngine();
config.setExpressionEngine(xpathEngine);
System.out.println(config.getBoolean("token/device/validate"));
System.out.println(config.getInt("token/person/expire"));
System.out.println(config.getString("token/person/expire/@description"));
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
如果上面两种表达式引擎都不合你的意,比如不喜欢/@description
和[@description]
这样的attribute标签(我就不喜欢)。你可以用自定义的符号规则生成一个DefaultExpressionEngine
表达式引擎对象。
下面的演示就是如何用@
做attribute的标签。
这部分的代码来自commons-configuration官网《Expression_engines》
@Test
public void test() {
try
{
DefaultExpressionEngineSymbols symbols =
new DefaultExpressionEngineSymbols.Builder(
DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS)
// 指定属性分隔符或可以用xpath的概念叫路径分隔符
.setPropertyDelimiter(".")
// Indices should be specified in curly brackets
.setIndexStart("{")
.setIndexEnd("}")
// 指定@开头就是attribute标志
.setAttributeStart("@")
// attribute结尾符为null
.setAttributeEnd(null)
// A Backslash is used for escaping property delimiters
.setEscapedDelimiter("\\/")
.create();
// 用自定义的符号DefaultExpressionEngineSymbols对象创建一个表达式引擎
DefaultExpressionEngine engine = new DefaultExpressionEngine(symbols);
Parameters params = new Parameters();
FileBasedConfigurationBuilder builder =
new FileBasedConfigurationBuilder(XMLConfiguration.class)
.configure(params.xml()
.setFileName("token.xml")
// 使用自定义的表达式引擎
.setExpressionEngine(engine));
XMLConfiguration config = builder.getConfiguration();
Configurations configs = new Configurations();
XMLConfiguration config2 = configs.xml(this.getClass().getClassLoader().getResource("token.xml"));
config2.setExpressionEngine(engine);
System.out.println(config.getBoolean("token.device.validate"));
System.out.println(config.getInt("token.person.expire"));
System.out.println(config.getProperty("token.person.expire@description"));
}
catch(Throwable e)
{
e.printStackTrace();
}
}
从properties中读取配置,如果不指定编码类型,是无法正常读取中文内容的。commons-configuration
中通过FileBasedConfigurationBuilder.setDefaultEncoding
方法来解决这个问题。示例如下:
@Test
public void test3(){
try
{
Configurations configs = new Configurations();
// setDefaultEncoding是个静态方法,用于设置指定类型(class)所有对象的编码方式。
// 本例中是PropertiesConfiguration,要在PropertiesConfiguration实例创建之前调用。
FileBasedConfigurationBuilder.setDefaultEncoding(PropertiesConfiguration.class, "UTF-8");
PropertiesConfiguration propConfig = configs.properties(this.getClass().getClassLoader().getResource("log4j.properties"));
System.out.println(propConfig.getString("log4j.appender.CONSOLE.Target"));
System.out.println(propConfig.getBoolean("log4j.appender.LOGFILE.Append"));
System.out.println(propConfig.getString("test"));
}
catch(Throwable e)
{
e.printStackTrace();
}
commons-configuration是允许使用变量的.比如
java.home =
${env:JAVA_HOME}
application.name = Killer App
application.version = 1.6.2
application.title =${application.name} ${application.version}
关于这部分的介绍看原文最好:《Variable_Interpolation》
相当多的应用场景中,一些配置都有默认参数,同时又允许用户修改这些默认参数 ,所以一般会把包含默认参数的配置文件打在jar包中。而允许用户在外部用额外的用户配置文件(比如在user.home文件夹下放用户自定义配置文件)来覆盖默认参数,这就是Overriding properties。
当然用户也可以不提供这个自定义配置文件,全部使用默认参数,也就是说这个自定义配置文件是可选的,这就是Optional configuration sources。
下面的例子就应用了commons-configuration
的这两个特性。
先定义一个root.xml,如下:
<configuration>
<properties fileName="${sys:user.home}/.facelog/config.properties" config-optional="true"/>
<xml fileName="defaultConfig.xml" />
configuration>
你可以把它当做一个配置文件的控制文件,它用来定义不同级别配置文件的优先级顺序,越往上面文件优先级越高可以覆盖下面文件中定义的变量。所以在最下面的就是默认配置文件,这就实现了Overriding properties。另外,除了最下面的默认配置文件外,上面的文件定义中都有指定config-optional="true"
它的意思就是这个文件是可选的,如果该文件不存在也不会报错抛出异常。
在定义配置文件位置时用到的${sys:user.home}
就是上一节提到的在配置文件中使用环境变量,${sys:user.home}
指定使用JVM系统属性”user.home”(Linux下就是$HOME
,Windows下就是%USERPROFILE%
)来指定文件位置.
有了这个root.xml
,就可以用Configurations.combined
方法生成一个CombinedConfiguration
对象,在${sys:user.home}
下的config.properties
定义的属性会覆盖defaultConfig.xml
中的值。
调用方法如下
@Test
public void test4(){
try
{
DefaultExpressionEngine engine = new DefaultExpressionEngine(DefaultExpressionEngineSymbols.DEFAULT_SYMBOLS);
Configurations configs = new Configurations();
// 创建CombinedConfiguration 实例
CombinedConfiguration config = configs.combined(this.getClass().getClassLoader().getResource("root.xml"));
config.setExpressionEngine(engine);
System.out.println(config.getBoolean("token.device.validate"));
System.out.println(config.getInt("token.person.expire"));
System.out.println(config.getString("token.person.expire[@description]"));
}
catch(Throwable e)
{
e.printStackTrace();
}
}