本文旨在探讨如何通过Apache Digester解决应用程序中的硬编码问题,特别是当需要通过修改文件而非重新编译代码来改变应用行为时。Apache Digester提供了一种简便的方法,能够将XML配置文件转换成Java Bean对象,从而实现灵活的应用配置管理。
Apache Digester的核心功能在于它能轻松地将XML文档解析并转换为对应的Java Bean对象层级结构。这一过程主要依赖于三个关键概念:
- 元素匹配模式:定义了XML文档中的元素如何与特定的处理规则相匹配。
- 处理规则:指定了如何处理匹配到的XML元素,包括创建对象、设置属性等操作。
- 对象堆栈:用于管理解析过程中创建的对象实例,确保它们能够正确地构建为所需的对象层级结构。
为了更好地理解这一过程,我们可以通过一个具体的例子来进行说明。假设你有一个包含数据的XML文件和一个或多个Java类,你的目标是从XML文件中读取数据,并创建这些Java类的实例。
具体步骤如下:
- 首先,在项目的类路径中加入Apache Digester 3的JAR文件,以及其他必要的库文件,如Commons Logging、BeanUtils和CGLIB。
- 如果尚未存在,根据XML文件的内容创建相应的Java类,反之亦然。注意,Java类和XML文件中的属性名称及结构应当保持一致,否则需要在规则文件中提供映射。
- 创建一个Digester规则文件,如digester-catalog-rules.xml,用于定义XML元素与Java类之间的映射关系。
- 编写少量的代码,使用Digester从XML文件中加载Java对象。
接下来,我们将通过一个实际的项目结构来展示这一过程的具体实现。
这是我的Eclipse项目结构:
任务2 - 创建一个名为chain-config.xml的数据XML文件,内容如下:
创建相应的Java类:
Catalog.java:
import java.util.ArrayList;
import java.util.List;
public class Catalog {
private String name;
private List chains = new ArrayList();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void addChains(Chain chain) {
this.chains.add(chain);
}
}
Chain.java:
import java.util.ArrayList;
import java.util.List;
public class Chain {
private String name;
private List commands = new ArrayList();
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void addCommands(Command command) {
this.commands.add(command);
}
}
Command.java:
public class Command {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
任务3 - 创建Digester规则文件digester-catalog-rules.xml:
任务4 - 编写客户端程序加载XML数据:
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.digester3.Digester;
import org.apache.commons.digester3.binder.DigesterLoader;
import org.apache.commons.digester3.xmlrules.FromXmlRulesModule;
import org.xml.sax.SAXException;
public class RunProgram {
public static void main(String[] args) {
DigesterLoader digesterLoader = DigesterLoader.newLoader(new FromXmlRulesModule() {
@Override
protected void loadRules() {
loadXMLRules(getClass().getResource("/com/tatu/resources/digester-catalog-rules.xml"));
}
});
Digester digester = digesterLoader.newDigester();
List catalogs = new ArrayList();
digester.push(catalogs);
InputStream input = Digester.class.getClass().getResourceAsStream("/com/tatu/resources/chain-config.xml");
try {
Object root = digester.parse(input);
} catch (IOException | SAXException e) {
e.printStackTrace();
}
}
}
至此,我们已经成功地使用XML数据加载了Catalogs对象。需要注意的是,Digester的规则非常直观且易于理解:
object-create-rule
用于创建一个新的对象实例。- 其他规则如
set-properties-rule
和bean-property-setter-rule
分别用于设置对象属性和嵌套元素的属性。 set-next-rule
用于处理递归结构,将新创建的对象添加到父对象的集合中。- 如果需要自定义规则,可以继承Digester的Rule类来创建自己的规则。
如果您在XML文件和Java类之间遇到映射问题,可以考虑使用Apache Betwixt作为替代方案。虽然使用Betwixt可能会牺牲一定的灵活性,但它提供了一种更简便的方法来实现Java Bean与XML文件之间的转换。
祝您编程愉快,欢迎分享您的经验和见解!
参考资料:本文内容基于Bijay Deo在JCG上的文章《使用Apache Digester进行配置》。