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 条评论
登录 后参与评论

相关文章

来自专栏蓝天

RPC的实现

RPC全称为Remote Procedure Call,即远过程调用。如果没有RPC,那么跨机器间的进程通讯通常得采用消息,这会降低开发效率,也会增加网络...

2123
来自专栏老马说编程

(87) 类加载机制 / 计算机程序的思维逻辑

上节,我们探讨了动态代理,在前几节中,我们多次提到了类加载器ClassLoader,本节就来详细讨论Java中的类加载机制与ClassLoader。 类加载...

1998
来自专栏皮皮之路

【JVM】浅谈双亲委派和破坏双亲委派

笔者曾经阅读过周志明的《深入理解Java虚拟机》这本书,阅读完后自以为对jvm有了一定的了解,然而当真正碰到问题的时候,才发现自己读的有多粗糙,也体会到只有实践...

2302
来自专栏Danny的专栏

【SpringDataJPA】——SpringDataJPA入门实例

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/huyuyang6688/article/...

1332
来自专栏向治洪

android classloader双亲委托模式

概述 ClassLoader的双亲委托模式:classloader 按级别分为三个级别:最上级 : bootstrap classLoader(根类加载器) ;...

2548
来自专栏无题

堆外内存概要

DirectByteBuffer JDK中使用 DirectByteBuffer对象来表示堆外内存,每个 DirectByteBuffer对象在初始化时,都会创...

2434
来自专栏李家的小酒馆

数据库JDBC的基本内容

JDBC 基本流程 首先向项目中导入jar包 创建如下代码 Class.forName("com.mysql.jdbc.Driv...

1930
来自专栏Hongten

java开发_模仿百度文库_SWFTools_源码下载

在之前有做了一篇文章:java开发_模仿百度文库_OpenOffice2PDF_源码下载

1052
来自专栏Java编程技术

结合JVM源码谈Java类加载器

之前文章 Java 类加载器揭秘 从Java层面讲解了Java类加载器的原理,这里我们结合JVM源码在稍微深入讲解下。

1071
来自专栏技术记录

通讯协议序列化解读(一) Protobuf详解教程

4747

扫码关注云+社区

领取腾讯云代金券