java:学习commons-configuration2读取配置文件xml,properties

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,这里做为笔记记录学习过程中的要点。

maven dependency

pom.xml 依赖配置如下,commons-beanutils,commons-jxpath对于commons-configuration2都是optional可选配件,但在本例都要用到所以必须加上否则运行会抛出异常 java.lang.ClassNotFoundException:

		<!-- https://mvnrepository.com/artifact/org.apache.commons/commons-configuration2 -->
		<dependency>
			<groupId>org.apache.commons</groupId>
			<artifactId>commons-configuration2</artifactId>
			<version>2.1.1</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/commons-beanutils/commons-beanutils -->
		<dependency>
			<groupId>commons-beanutils</groupId>
			<artifactId>commons-beanutils</artifactId>
			<version>1.9.3</version>
		</dependency>
		<!-- https://mvnrepository.com/artifact/commons-jxpath/commons-jxpath -->
		<dependency>
			<groupId>commons-jxpath</groupId>
			<artifactId>commons-jxpath</artifactId>
			<version>1.3</version>
		</dependency>

xml 表达式引擎

相比properties文件格式 xml要复杂多了(每个节点都可以有attribute),所以对于xml格式的配置文件,访问一个元素的值或attribute需要一套表达式规则来规定。比如路径节点用.分隔,attribute用@开头。commons-configuration提供了默认规则,但这个规则用户也是可以自定义的,也可以使用xpath标准。
下面的代码演示如何使用默认规则、xpath、自定义规则来访问Xml配置文件中的节点.
先贴出演示用的xml文件。
token.xml,放在源码根目录下,是一个很简单的配置文件,其中的description是节点属性。

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
	<token>
		<device>
			<validate>true</validate>
		</device>
		<person>
			<validate>true</validate>
			<expire description="人员令牌失效时间(分钟) ">60</expire>
		</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<XMLConfiguration> builder =
			    new FileBasedConfigurationBuilder<XMLConfiguration>(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文件编码

从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,如下:

<?xml version="1.0" encoding="UTF-8"?>
<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();
		}
	}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

10km

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值