How tomcat works 读书笔记十五 Digester库 上
Digester库
在前面的几个章节里,我们对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; } }
How tomcat works 读书笔记十五 Digester库 上的更多相关文章
- How tomcat works 读书笔记十五 Digester库 下
在这一节里我们说说ContextConfig这个类. 这个类在很早的时候我们就已经使用了(之前那个叫SimpleContextConfig),但是在之前它干的事情都很简单,就是吧context里的co ...
- How tomcat works 读书笔记十四 服务器组件和服务组件
之前的项目还是有些问题的,例如 1 只能有一个连接器,只能处理http请求,无法添加另外一个连接器用来处理https. 2 对容器的关闭只能是粗暴的关闭Bootstrap. 服务器组件 org.apa ...
- How tomcat works 读书笔记十二 StandardContext 下
对重载的支持 tomcat里容器对重载功能的支持是依靠Load的(在目前就是WebLoader).当在绑定载入器的容器时 public void setContainer(Container cont ...
- How tomcat works 读书笔记十二 StandardContext 上
在tomcat4中,StandardContext.java是最大的一个类,有117k.废话不说,开始分析吧. 其实要分析StandardContext,也就主要分析两个方法,一个start,一个in ...
- How Tomcat Works 读书笔记 八 加载器 上
Java的类加载器 具体资料见 http://blog.csdn.net/dlf123321/article/details/39957175 http://blog.csdn.net/dlf1233 ...
- how tomcat works 读书笔记(二)----------一个简单的servlet容器
app1 (建议读者在看本章之前,先看how tomcat works 读书笔记(一)----------一个简单的web服务器 http://blog.csdn.net/dlf123321/arti ...
- how tomcat works 读书笔记四 tomcat的默认连接器
事实上在第三章,就已经有了连接器的样子了,只是那仅仅是一个学习工具,在这一章我们会開始分析tomcat4里面的默认连接器. 连接器 Tomcat连接器必须满足下面几个要求 1 实现org.apache ...
- how tomcat works读书笔记 七 日志记录器
大家可以松一口气了,这个组件比较简单,这一节和前面几节想比,也简单的多. Logger接口 Tomcat中的日志记录器都必须实现org.apache.catalina.Logger接口. packag ...
- How Tomcat Works读书笔记三-------连接器
几个概念 HttpServlet,Servlet Servlet是一个接口,定义了一种网络服务,我们所有的servlet都要实现它(或它的子类) HttpServlet是一个抽象类,它针对的就是htt ...
随机推荐
- SQLite 删除表(http://www.w3cschool.cc/sqlite/sqlite-drop-table.html)
SQLite 删除表 SQLite 的 DROP TABLE 语句用来删除表定义及其所有相关数据.索引.触发器.约束和该表的权限规范. 使用此命令时要特别注意,因为一旦一个表被删除,表中所有信息也将永 ...
- Linux日志管理高级进阶:实例详解syslog
syslog已被许多日志函数采纳,它用在许多保护措施中,任何程序都可以通过syslog记录事件.syslog可以记录系统事件,可以写到一个文件或设备中,或给用户发送一个信息.它能记录本地事件或通过网络 ...
- 【一天一道Leetcode】#190.Reverse Bits
一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 我的个人博客已创建,欢迎大家持续关注! 一天一道le ...
- spring 的OpenSessionInViewFilter简介
假设在你的应用中Hibernate是通过spring 来管理它的session.如果在你的应用中没有使用OpenSessionInViewFilter或者OpenSessionInViewInterc ...
- android RecycleView Adapter简单封装
早些时候我们使用系统提供个的BaseAdapter的时候为了满足大家的需要,我们总会对BaseAdapter做一层上层的封装,然后对于实际业务我们只需要关心getView里面的View即可,是代码可读 ...
- UNIX网络编程——常用服务器模型总结
下面有9种服务器模型分别是: 迭代服务器. 并发服务器,为每个客户fork一个进程. 预先派生子进程,每个子进程都调用accept,accept无上锁保护. 预先派生子进程,以文件锁的方式保护acce ...
- Spark技术内幕:Master基于ZooKeeper的High Availability(HA)源码实现
如果Spark的部署方式选择Standalone,一个采用Master/Slaves的典型架构,那么Master是有SPOF(单点故障,Single Point of Failure).Spark可以 ...
- J2EE进阶(十)SSH框架整合常见问题汇总(一)
SSH框架整合常见问题汇总(一) 前言 以下所列问题具有针对性,但是遇到同类型问题时均可按照此思路进行解决. HTTP Status 404 - No result defined for actio ...
- mysql的left jion:就是left outer join(right join同理)
左外连接: A left jion B on A.id=B.id 就是A表数据不动,将B表里面能和A对应上的数据补充到A表数据后 而右外连接: rignt jion 则是将A补充到B,B不动,保存全部 ...
- JAVA对象克隆可能会出现的问题
首先,区分一下拷贝和克隆: 拷贝:当拷贝一个变量时,原始变量与拷贝变量引用的是同一个对象.当改变一个变量所引用的对象,则会对另一个变量造成影响. 克隆:当克隆一个对象时,是重新的创建了和该对象内容相同 ...