在很多系统中,需要用到配置文件来存放配置参数。配置参数从代码中单独提出来主要是为了方便修改用的。常见的一个用法是将数据库连接参数(数据库服务器 IP,用户名,密码等等)写在一个配置文件中,这主要是系统可能会更换数据库,或者网络可能更换 IP 地址范围,或者服务器 IP 可能会变动等等。
配置参数不仅限于配置文件,也可以保存在其他地方,比如数据库单独用一个表保存配置参数,或者在内存中,或者在操作系统环境变量中,等等。有个现成的读写配置数据工具包,让人感觉很不错。
早期的配置文件主要用 ini 文件,或者类似 ini 文件格式。这种配置文件格式简单,相应的读写工具类也很容易写,各种开发语言基本上都能在网上找到现成的代码。其主要特点是 key <--> value 对应。ini 文件是纯文本文件,对于不是程序员的最终用户,修改 ini 配置文件也没有太多的难度。相比较而言,其他格式的配置都比 ini 有更大的难度。
可惜的是 Common Configuration 工具包不支持 ini 格式。文档中说它支持的配置参数来源有:
* Properties files
* XML documents
* Property list files (.plist)
* JNDI
* JDBC Datasource
* System properties
* Applet parameters
* Servlet parameters
数据形式也不限于 key <--> value 形式,Common Configuration 工具包也支持树形结构的参数配置。
Common Configuration 工具包体系比较简单。一个基本的 Configuration interface 定义了各种配置通用的操作,一个 AbstractConfiguration 从 Configuration interface 下来将所有公用的操作实现了,留下一个不通用的函数 getProperty, setProperty 等待子类实现。真正有实际操作的 DatabaseConfiguration、PropertiesConfiguration、XMLConfiguration、XMLPropertiesConfiguration、MapConfiguration 等等,都是从 AbstractConfiguration 继承。MapConfiguration 是基于内存操作的配置参数读写工具类,XMLPropertiesConfiguration 则是基于 XML 文件的模仿 java properties 格式的配置文件读写工具类。有点怪吧?主要是因为 java property 文件本来设计只是为了存放多语言字符串用的,有的 java 程序员希望在 java 中有类似 INI 文件的配置文件,但是 JDK 中没有现成的工具类,只能用 property 文件凑合着用。举例来说, log4j 就可以用 property 格式的配置文件。但是这种格式的配置文件有个很大的弱点,如果里面包含非 ASCII 字符,比如说是中文,必须要写成 UNICODE 编码格式。如果软件交付给用户,用户需要改一个参数,用户没有办法改这种 property 文件。XMLPropertiesConfiguration 使用的是 XML 格式配置文件,一般用 UTF-8 编码,这种文件可以用常用操作系统自带的软件来修改(比如 windows 的记事本程序),因而更加方便。XML property 格式配置文件现在已经用得比较多了,在 J2SE 5.0 中也定义了一种 XML property 格式,这里的 XMLPropertiesConfiguration 工具类就是遵循这种格式标准。
Configuration interface 定义了一些基本操作:addProperty, clear, clearProperty, containsKey, getBigDecimal, getBigInteger, getBoolean, getByte,getDouble,getFloat,getInt, getKeys, getList, getLong, getProperties, getProperty, getShort, getString, getStringArray, isEmpty, setProperty 等等。看起来还是比较齐全。也可以用 DataConfiguration 将已有的 Configuration 重新包装一下,然后可以读写其它类型的配置参数:URL, Locale, Date, Calendar, Color, 以及各种形式对象的 lists 和 arrays。DataConfiguration 主要做的事情是在读写配置数据的时候将这些额外的类型数据与 String 类型相互转换,最终所有配置参数还是保存成 String 形式。
这里面还有另外一个类 CompositeConfiguration, 可以将几个 Configuration 并在一起用,这不太常见,偶尔会用到。举例来说,将数据库连接参数放在文件型配置文件中,将系统其他参数放在数据库中是一个比较常见的设计。如果几个程序员同时调试程序,可能需要将数据库中同一个配置参数设置成不同的值,这个时候就比较麻烦,要吵架了。这个时候可以将文件型配置和数据库配置做成一个组合配置CompositeConfiguration, 优先读取文件型配置中参数,如果文件型配置参数中没有才读取数据库中参数。这样就可以解决了。真正最后系统交付的时候把所有配置放在数据库中,只留下数据库连接配置放在文件型配置中。
值得注意的是,有的 Configuration 性能不够优化,可能需要自己写一个相应的子类将 getProperty, setProperty 等函数重新写一下。现成的思路是,DatabaseConfiguration 每次 getProperty 都读取一次数据库,如果不是在集群环境,可以把所有配置数据一次读出放在一个 map 中,这样每次 getProperty 速度快很多。
无论如何,Common Configuration 是一个非常优秀的 java 工具包。我注意到,在它的开发 roadmap 中,INI 格式配置计划在 1.3 版本中支持,应该说 INI 格式不难,不知道为什么要放到 1.3 版本中才能实现。1.3 版本还计划支持 windows 注册表格式的配置,个人觉得没有什么大的用处。其他有些稀奇古怪的计划,可能是有的开发人员提出的不太通用的一些要求。从目前的开发版本的 bugzilla 上面看,没有较核心的 bug ,比较让人放心,值得推荐。