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();
        }
    }

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏生信技能树

肿瘤全外显子测序数据分析流程大放送

这个一个肿瘤外显子项目的文章发表并且公布的公共数据,我这里给出全套分析流程代码。只需要你肯实践,就可以运行成功。 PS:有些后起之秀自己运营公众号或者博客喜欢批...

6198
来自专栏闻道于事

js登录滑动验证,不滑动无法登陆

js的判断这里是根据滑块的位置进行判断,应该是用一个flag判断 <%@ page language="java" contentType="text/html...

3738
来自专栏PPV课数据科学社区

【学习】七天搞定SAS(四):数据输出

弄清楚了基本的PROC之后,开始研究SAS的输出...毕竟有了数据处理的结果之后,还要有一个比较舒服的输出格式才可以嘛。 SAS的结果发送系统:ODS SAS里...

3078
来自专栏杂烩

SSM项目搭建三(终) 原

903
来自专栏移动端周边技术扩展

iOS 7 之后UITextView 最后一行显示bug

1665
来自专栏WOLFRAM

罗马曲面的旋转

1247
来自专栏飞雪无情的博客

Android ViewGroup.setDescendantFocusability函数

这个函数是在ViewGroup里定义的,主要用于控制child View获取焦点的能力,比如是否阻止child View获取焦点。

521
来自专栏专知

2018年SCI期刊最新影响因子排行,最高244,人工智能TPAMI9.455

2018年6月26日,最新的SCI影响因子正式发布,涵盖1万2千篇期刊。CA-Cancer J Clin 依然拔得头筹,其影响因子今年再创新高,达244.585...

952
来自专栏Android干货

Android项目实战(八):列表右侧边栏拼音展示效果

2755
来自专栏deepcc

emmet(Zen coding)帮助文档

2735

扫码关注云+社区