CPAN AppConfig 模块和面向数据库的配置 |
级别: 初级 Teodor Zlatanov (tzz@iglou.com), 程序员, Gold Software Systems 2000 年 10 月 09 日 如果您使用手工构建的方法,那么基于文件的配置很快就会崩溃。Teodor Zlatanov 演示了 AppConfig 模块如何处理用于 Perl 程序的本地配置存储,以及如何将这些配置存储到数据库中,以便随后能从网络上的任何机器进行访问。 程序(从低级的列目录程序到 Web 浏览器)的首要需求之一是:它应该是可配置的。事实证明,基于文件的可配置性和命令行选项的组合是针对可配置性需要的长期而又灵活的解决方案。Perl 程序通常采用这种方法,尽管它们往往还包括一个配置文件和命令行解析例程。 我们将在本文中使用的命令行解析有一点复杂。因此,为了避免进一步的混淆,如果您正在进行的解析等级高于简单参数,我建议您使用 Parse::RecDescent(或等价的解析模块)。有关复杂命令行解析的讨论,请参阅我关于说英语的 Perl 程序的 前一篇文章。 在开始之前,请确保您已经在系统上安装了 Perl 5.005(或更新版本)和 CPAN AppConfig 模块。您还需要 Persistent::MySQL 或适用于您的特定数据库的 Persistent 类。这些都可以在 CPAN 中获取(请参阅本文后面的 参考资料)。 理论上(并在有适当工具的情况下!)任何人都可以构建配置解析器,对吗?举例来说, Perl Cookbook展示了一个提供良好开端的快速实现。那么,如果您从此类实现开始的话,编写一个配置文件解析器有多难呢? 实际上相当困难,因为此类项目涉及如下几个比较复杂的问题:
您已经害怕了?这就是我们使用 AppConfig 的原因。它可以处理所有这些问题。很清楚的一点是,您不应该使用 DIY。
尽管 Andy Wardley 编写的 AppConfig CPAN 模块有助于解决上面列出的所有问题,但它不是万能的。它不可能魔术般地改进您的程序。有时需要重新编写以使用 AppConfig。(也存在一点学习曲线,本文试图帮助您降低学习的难度。) 显然,如果您不确定应该使用 DIY 还是 AppConfig,那么应该根据您的经验和正在编写的内容作出决定。但我相信,AppConfig 不能做得象 DIY 一样好或更好这种情况是非常少的。 关于 AppConfig 能为您做些什么,以下将逐点进行说明(按照前一节的问题列表):
既然我们已经看到了很多选用 AppConfig 的好理由,那么,让我们看一下完整的带注释的 AppConfig 用法示例。目前,我们将省略许多比较高级的特性(将在下一节中讨论)。可以从命令行用“-varname value”设置标量、布尔型和数组变量,用“-varname key=value”设置散列变量。此处用的配置文件是 config.pl,以下是示例:
AppConfig 可以在几个级别上进行变量扩展,这取决于 EXPAND 设置。有关更多详细信息请参阅 AppConfig 文档。
INI 样式的节是 AppConfig 的另一个特性,您会发现它很有用。通过在配置文件中使用 [节](它本身占一行),您可以列出在文件结束前使用的所有关键字,也可以使用节名加上下划线‘_’列出本节和下一节的所有关键字。例如:
等价于:
可以用 varlist() 函数检查 AppConfig 配置对象。下面的代码打印了 AppConfig 对象中每个变量的内容。注:varlist() 可能有点麻烦,因为它必须采用正则表达式(空字符串是绝对无效的)。
AppConfig 中有一个 Getopt::Long 接口,它允许访问 Getopt::Long 模块的所有功能。下面的代码定义了 Getopt::Long 的变量参数,调用该段代码以解析来自命令行的参数。无效值会引起错误。
AppConfig 中还可以进行变量验证。这意味着通过引用正则表达式(或者甚至是一段代码),变量会拒绝将其值设置为某些恶意的值或完全无意义值的尝试。
AppConfig 使自动触发操作成为可能,因此每次变量的值更改时,该操作就会执行。注:对 AppConfig 的引用也被传送到子例程,所以单个更改会触发其它变量更改。
AppConfig 不处理变量中嵌入的代码。在我看来,配置文件中无论如何都不应该存在代码,并且允许用户执行任意代码是个坏主意。但是,AppConfig 不提供对变量的自动求值,尽管确实可以协调与变量相关联的验证和自动操作子例程来执行这项任务。如果您确实感到对此有强烈的需求,那么挑出有疑问的变量并自己针对它们运行 eval()(以下面所阐述的方法)。不用说,除非您完全希望将对您的程序的这一级别的控制权赋予用户,否则就 不要这样做。
AppConfig 中 INI 样式的节不是很重要。它们定义代码节,但在使用之前必须预先知道这些节。最好先把节设计好,以便它们创建嵌套在父对象中的新 AppConfig 对象,但这是个次要问题。 在简单测试中,使用 AppConfig 似乎不影响装入和执行速度。它是个相当小的模块,其大小/速度代价通常可以忽略不计。当然,如果您的程序对时间很敏感,那么您应该针对使用和不使用 AppConfig 的情况分别对它计时,然后自己决定是否值得使用该模块。 AppConfig 的复杂程度和学习曲线之所以比您原来预期的要低很多,很大程度上是因为出色的 API。这里有使人混淆的地方(尤其对新程序员更是如此),但总的来说,对于任何原先具有 Perl 经验的人,这不是很重要的问题。 AppConfig 的解析限制在于其可用性。如果您需要命令行选项的高级解析,请参阅有关说英语的 Perl 程序的 前一篇文章。(这一限制与 AppConfig 不能进行上下文敏感的解析有特殊的关系。)
用 AppConfig 和 Persistent::DBI 将配置上载到数据库 我建议在阅读本节之前,阅读我关于 用 Persistent 模块保存数据的文章。您还应该对 Perl 引用和 SQL 数据库有一定理解。我特定的代码示例使用了 MySQL 数据库以及相应的 Persistent 模块。如果您正在使用另一种数据库(例如 Postgres 或 Oracle),则应该寻找其它 Persistent 模块。 在配置可用于数据库环境之前,必须先设计数据库模式。换句话说,在开始编写用来保存和恢复数据的代码 之前,您需要确定希望保存什么数据。这个示例将在不同表中存储布尔值、标量、数组和散列。 这未必是最佳途径。您也可以将一个表用于所有数据类型,或按用途划分表。我的示例仅是实现持久配置的许多方法之一。它肯定不是仅有的方法。 我在此处提供的模式可能对于大多数用途都足够了。它确实对于值和键长度有一些限制,但可以在代码中轻松地调整那些限制。但是,创建数组和散列元素标识的方法可能引起问题。在这些情况下没有完美的解决方案,只有解决问题的不同方法。将任意的结构化数据存储到关系数据库总是麻烦的。 我们将使用 AppConfig::State 中的 _argcount() 方法。有关这个方法的更详细信息,请阅读 AppConfig::State 的手册页。简单来说,如果我们知道变量名,该方法就可以告诉我们正在处理什么类型的变量。 在我的代码示例中,我使用了 MySQL 数据库和相应的 Persistent 模块: persistent-config.pl。
只要做少量工作,就可以使 AppConfig 和 Persistent 类很好地合作。前一节中展示的持久配置脚本可以处理大多数具有短键和变量名的配置,但还有可改进的余地。在按自己的喜好编写完脚本后,就可以在网络的 任何地方启动它,并让它从中央主机载入当前配置。至少,进行改进将教会您关于数据库配置的知识,并有助于您以网络为中心的新方式研究应用程序。 代码重用通常是模块唯一最大的好处,尤其对 AppConfig 更是这样。对于 DIY(自己动手)方法产生了错误和延迟的情况,AppConfig 提供了有效的单一解决方案,该方案很可能可以满足大多数配置需求。 “AppConfig 限制”一节所列出的限制非常少。当然,在选用 AppConfig 之前,您应该确定对于您的项目什么才是最适合的。最好牢记如何将此处提供的信息应用于您的特定项目,并研究 AppConfig 手册页。 现在干什么呢?您应该从 AppConfig 中只采用您所需要的。而不要尝试让它为您做所有的工作。将一半程序放到一个配置文件中看来挺有趣,但如果这样做,不久以后用户就会咆哮着冲进您的办公室。请使您的配置文件有逻辑性而又简单。编写程序接受的配置语法的详细说明,包括 AppConfig 提供的非常周到的命令行选项。 |