Digester库
在前面的几个章节里,我们对tomcat里各个组件的配置完全是使用写硬编码的形式完成的。
如
这么做的问题就在于,一旦我想更改配置就必须得重新加载Bootstrap类。
幸运的是tomcat的设计者使用了一种给我灵活的配置方式,即使用xml来记录tomcat里各个组件的配置情况。并且使用Digester将xml中的元素转化为java对象。
Digester是Apache软件基金会Jakarta项目下的一个开源项目。更多具体的信息请问百度。
这里我们主要介绍Digester能干什么。
在apaceh官网上对这个项目的描述如下
XML-to-Java-object mapping utility.
看到了吧,就是咱们在上面说的把xml里面的元素转化为java类。
在讨论Digester如何解析xml前,我们先说两个概念,模式与规则。
模式:我无法给出一个书面的关于模式的定义。粗略的说在上面的xml中,employee元素的模式是employee;office元素的模式是employee/office;以此类推address元素的模式就是employee/office/address。大家应该大概明白了吧。说白了模式就是路径。
规则:是org.apache.commons.digester.Rule类的实例。规则指定了在分析xml时遇到某一规则应该执行的动作。说的够清楚了吧。另外Rule还有begin与end方法。挡在解析到匹配某个模式的元素的开始标签时会指向begin方法,end还用说吗?
例如在解析上面的xml时:
1 先解析到了employee元素,此时查找是否有对应的规则与此模式即employee匹配,若有,执行Rule对象的begin方法
2 遇到了office元素,此时查找是否有对应的规则与此模式即employee/office匹配,若有,执行Rule对象的begin方法
3 遇到了address元素的开始标签,此时查找是否有对应的规则与此模式即employee/office/address匹配,若有,执行Rule对象的begin方法
4 遇到address元素的结束标签,调用想匹配规则对象的end方法。
5 6自己补全,我不写了。
Digester预定义的规则
Digester预定义的规则主要有以下几个。
最主要的两个例子如下:
digester.addObjectCreate("employee",ex15.pyrmont.digestertest.Employee.class);
或者
digester.addObjectCreate("employee","ex15.pyrmont.digestertest.Employee");
第一个参数是模式名,第二个参数可以是类名(String类型),也可以使Class。
还有两种方式就是在xml中写明要加载的类。
若xml中如下
<employee firstName="Brian" lastName="May"
className="ex15.pyrmont.digestertest.Employee">
代码写成下面的样子
digester.addObjectCreate("employee","ex15.pyrmont.digestertest.Employee", "className");
上面这句代码做的事情就是:系统找到匹配employee模式的元素后,如果那个元素有属性,就将相应的属性值注入到类里面去。
<employee firstName="Brian" lastName="May">
如果xml中如上,里面在它所匹配的那个类里面就至少得有setFirstName,setLastName两个方法。
上面代码的功能就是找到匹配employee模式的元素后(准确的说是遇到结束标签后),就调用最先创建的那个类的printName方法。
第一个参数的模式应该是这种形式的
firstobject/secondobjcet
上面的代码的意思就是调用firstobject的addOffice方法,并且以secondobject为参数。当然这两个object前面都已经产生好了。
下面这个例子让大家熟悉一下Digester的用法
示例代码1
employee2.xml如下
Rule类
rule,顾名思义就是规则,就是当解析器解析到某个模式时要干什么事。
可能大家要问,不是已经有前面的addObjectCreate了么?问题是如果我想让程序每解析出一个"类"就做个什么事怎么办?创建一个类只是各种规则的一种而已。
org.apache.commons.digester.rule里面有两个方法比较重要,分别是begin与end。
public void begin(Attributes attributes) throws Exception
public void end() throws Exception
当在解析到某种模式的是时候,遇到开始标签就调用begin方法,结束标签就调用end方法。
现在我们说说之前的addObjectCreate方法。
rules是一个接口 我们使用的是它的实现类RulesBase
在RulesBase中有下面的代码
换言之,包括addObjectCreate在内前面说的几个预定义规则干的事情就是在Digester的rules里面添加一个rule而已。
等到扫描器扫描到指定的模式时,就执行指定的rule里的begin,end。
大家看代码就懂了。
RuleSetBase就是规则的集合嘛。
Test03与Test02的结果一样,但是test3的代码看起来更少一些,就是因为我们把规则都隐藏在了EmployeeRuleSet里面了。
在前面的几个章节里,我们对tomcat里各个组件的配置完全是使用写硬编码的形式完成的。
如
Context context = new StandardContext();
Loader loader = new WebappLoader();
context.setLoader(loader);
就完成了向context容器里添加WepappLoader的功能。
这么做的问题就在于,一旦我想更改配置就必须得重新加载Bootstrap类。
幸运的是tomcat的设计者使用了一种给我灵活的配置方式,即使用xml来记录tomcat里各个组件的配置情况。并且使用Digester将xml中的元素转化为java对象。
Digester是Apache软件基金会Jakarta项目下的一个开源项目。更多具体的信息请问百度。
这里我们主要介绍Digester能干什么。
在apaceh官网上对这个项目的描述如下
XML-to-Java-object mapping utility.
看到了吧,就是咱们在上面说的把xml里面的元素转化为java类。
Digester类
先看一个xml 如下<?xml version="1.0" encoding="ISO-8859-1"?>
<employee firstName="Freddie" lastName="Mercury">
<office description="Headquarters">
<address streetName="Wellington Avenue" streetNumber="223"/>
</office>
</employee>
在这个xml里面,根元素是employee,里面包含一个元素office,office里面又包含一个元素address。
在讨论Digester如何解析xml前,我们先说两个概念,模式与规则。
模式:我无法给出一个书面的关于模式的定义。粗略的说在上面的xml中,employee元素的模式是employee;office元素的模式是employee/office;以此类推address元素的模式就是employee/office/address。大家应该大概明白了吧。说白了模式就是路径。
规则:是org.apache.commons.digester.Rule类的实例。规则指定了在分析xml时遇到某一规则应该执行的动作。说的够清楚了吧。另外Rule还有begin与end方法。挡在解析到匹配某个模式的元素的开始标签时会指向begin方法,end还用说吗?
例如在解析上面的xml时:
1 先解析到了employee元素,此时查找是否有对应的规则与此模式即employee匹配,若有,执行Rule对象的begin方法
2 遇到了office元素,此时查找是否有对应的规则与此模式即employee/office匹配,若有,执行Rule对象的begin方法
3 遇到了address元素的开始标签,此时查找是否有对应的规则与此模式即employee/office/address匹配,若有,执行Rule对象的begin方法
4 遇到address元素的结束标签,调用想匹配规则对象的end方法。
5 6自己补全,我不写了。
Digester预定义的规则
Digester预定义的规则主要有以下几个。
创建对象
创建对象一共有四种方式最主要的两个例子如下:
digester.addObjectCreate("employee",ex15.pyrmont.digestertest.Employee.class);
或者
digester.addObjectCreate("employee","ex15.pyrmont.digestertest.Employee");
第一个参数是模式名,第二个参数可以是类名(String类型),也可以使Class。
还有两种方式就是在xml中写明要加载的类。
若xml中如下
<employee firstName="Brian" lastName="May"
className="ex15.pyrmont.digestertest.Employee">
代码写成下面的样子
digester.addObjectCreate("employee","ex15.pyrmont.digestertest.Employee", "className");
employee是类名,程序会按照上面方法的第三个参数去employee元素里找对应的属性值作为要加载的类,当然如果找不到那个属性的话,就是有上面方法的第二个参数来加载。同样第二个参数可以使String类型的类名也可以使Class。
(employee,office,address都在文章的最后)
设置属性
digester.addSetProperties("employee");上面这句代码做的事情就是:系统找到匹配employee模式的元素后,如果那个元素有属性,就将相应的属性值注入到类里面去。
<employee firstName="Brian" lastName="May">
如果xml中如上,里面在它所匹配的那个类里面就至少得有setFirstName,setLastName两个方法。
调用方法
digester.addCallMethod("employee", "printName");上面代码的功能就是找到匹配employee模式的元素后(准确的说是遇到结束标签后),就调用最先创建的那个类的printName方法。
创建对象之间的联系
digester.addSetNext("employee/office", "addOffice");第一个参数的模式应该是这种形式的
firstobject/secondobjcet
上面的代码的意思就是调用firstobject的addOffice方法,并且以secondobject为参数。当然这两个object前面都已经产生好了。
下面这个例子让大家熟悉一下Digester的用法
示例代码1
package ex15.pyrmont.digestertest;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.commons.digester.Digester;
public class Test02 {
public static void main(String[] args) {
String path = System.getProperty("user.dir") + File.separator +
"src"+File.separator + "etc";
File file = new File(path, "employee2.xml");
Digester digester = new Digester();
// add rules
digester.addObjectCreate("employee", "ex15.pyrmont.digestertest.Employee");
digester.addSetProperties("employee");
digester.addCallMethod("employee", "printName");
digester.addObjectCreate("employee/office", "ex15.pyrmont.digestertest.Office");
digester.addSetProperties("employee/office");
digester.addSetNext("employee/office", "addOffice");
digester.addObjectCreate("employee/office/address", "ex15.pyrmont.digestertest.Address");
digester.addSetProperties("employee/office/address");
digester.addSetNext("employee/office/address", "setAddress");
try {
Employee employee = (Employee) digester.parse(file);
ArrayList<?> offices = employee.getOffices();
Iterator<?> iterator = offices.iterator();
System.out.println("-------------------------------------------------");
while (iterator.hasNext()) {
Office office = (Office) iterator.next();
Address address = office.getAddress();
System.out.println(office.getDescription());
System.out.println("Address : " +
address.getStreetNumber() + " " + address.getStreetName());
System.out.println("--------------------------------");
}
}
catch(Exception e) {
e.printStackTrace();
}
}
}
employee2.xml如下
<?xml version="1.0" encoding="ISO-8859-1"?>
<employee firstName="Freddie" lastName="Mercury">
<office description="Headquarters">
<address streetName="Wellington Avenue" streetNumber="223"/>
</office>
<office description="Client site">
<address streetName="Downing Street" streetNumber="10"/>
</office>
</employee>
至于最后的运行结果大家自己猜一下,然后运行一下看看。
Rule类
rule,顾名思义就是规则,就是当解析器解析到某个模式时要干什么事。
可能大家要问,不是已经有前面的addObjectCreate了么?问题是如果我想让程序每解析出一个"类"就做个什么事怎么办?创建一个类只是各种规则的一种而已。
org.apache.commons.digester.rule里面有两个方法比较重要,分别是begin与end。
public void begin(Attributes attributes) throws Exception
public void end() throws Exception
当在解析到某种模式的是时候,遇到开始标签就调用begin方法,结束标签就调用end方法。
现在我们说说之前的addObjectCreate方法。
Digester.java
protected Rules rules = null;
public void addObjectCreate(String pattern, Class clazz) {
addRule(pattern,new ObjectCreateRule(clazz));
}
public void addRule(String pattern, Rule rule) {
rule.setDigester(this);
getRules().add(pattern, rule); //getRules返回的就是Digester中的那个rules
}
ObjectCreateRule.java
public void begin(Attributes attributes) throws Exception {
....
// Instantiate the new object and push it on the context stack
Class clazz = digester.getClassLoader().loadClass(realClassName);
Object instance = clazz.newInstance();
digester.push(instance);
}
Digester里面存储了一个rules对象
rules是一个接口 我们使用的是它的实现类RulesBase
在RulesBase中有下面的代码
protected ArrayList rules = new ArrayList();
另外ObjectCreateRule也是rule的子类。
换言之,包括addObjectCreate在内前面说的几个预定义规则干的事情就是在Digester的rules里面添加一个rule而已。
等到扫描器扫描到指定的模式时,就执行指定的rule里的begin,end。
RuleSet
这是什么东西?大家看代码就懂了。
package ex15.pyrmont.digestertest;
import java.io.File;
import java.util.ArrayList;
import java.util.Iterator;
import org.apache.commons.digester.Digester;
public class Test03 {
public static void main(String[] args) {
String path = System.getProperty("user.dir") + File.separator +
"src"+File.separator + "etc";
File file = new File(path, "employee2.xml");
Digester digester = new Digester();
digester.addRuleSet(new EmployeeRuleSet()); //EmployeeRuleSet是什么东西?
try {
Employee employee = (Employee) digester.parse(file);
...... 与Test2一样
}
catch(Exception e) {
e.printStackTrace();
}
}
}
package ex15.pyrmont.digestertest;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.RuleSetBase;
//一定要继承RuleSetBase
public class EmployeeRuleSet extends RuleSetBase {
//复写 addRuleInstances
public void addRuleInstances(Digester digester) {
// add rules
digester.addObjectCreate("employee", "ex15.pyrmont.digestertest.Employee");
digester.addSetProperties("employee");
digester.addObjectCreate("employee/office", "ex15.pyrmont.digestertest.Office");
digester.addSetProperties("employee/office");
digester.addSetNext("employee/office", "addOffice");
digester.addObjectCreate("employee/office/address","ex15.pyrmont.digestertest.Address");
digester.addSetProperties("employee/office/address");
digester.addSetNext("employee/office/address", "setAddress");
}
}
RuleSetBase就是规则的集合嘛。
Test03与Test02的结果一样,但是test3的代码看起来更少一些,就是因为我们把规则都隐藏在了EmployeeRuleSet里面了。
相关代码
package ex15.pyrmont.digestertest;
import java.util.ArrayList;
public class Employee {
private String firstName;
private String lastName;
private ArrayList<Office> offices = new ArrayList<Office>();
public Employee() {
System.out.println("Creating Employee");
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
System.out.println("Setting firstName : " + firstName);
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
System.out.println("Setting lastName : " + lastName);
this.lastName = lastName;
}
public void addOffice(Office office) {
System.out.println("Adding Office to this employee");
offices.add(office);
}
public ArrayList<Office> getOffices() {
return offices;
}
public void printName() {
System.out.println("My name is " + firstName + " " + lastName+"sssssssss");
}
}
package ex15.pyrmont.digestertest;
public class Office {
private Address address;
private String description;
public Office() {
System.out.println("..Creating Office");
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
System.out.println("..Setting office description : " + description);
this.description = description;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
System.out.println("..Setting office address : " + address);
this.address = address;
}
}
package ex15.pyrmont.digestertest;
public class Address {
private String streetName;
private String streetNumber;
public Address() {
System.out.println("....Creating Address");
}
public String getStreetName() {
return streetName;
}
public void setStreetName(String streetName) {
System.out.println("....Setting streetName : " + streetName);
this.streetName = streetName;
}
public String getStreetNumber() {
return streetNumber;
}
public void setStreetNumber(String streetNumber) {
System.out.println("....Setting streetNumber : " + streetNumber);
this.streetNumber = streetNumber;
}
public String toString() {
return "...." + streetNumber + " " + streetName;
}
}