1、Digester是Apache软件基金会的Jakarta项目下的子Commons项目下的一个开源项目,Digester API包含3个包:org.apache.commons.digester,提供了基于规则的、可处理任意XML文档的类,org.apache.commons.digester.rss包含了一些可以用来解析与很多新闻源使用的RSS格式兼容的XML文档的例子,org.apache.commons.digester.xmlrules为Digester库提供了一些规则基于XML的定义;

2、比如在tomcat中要实例话一个Context对象,可以用下面的代码:

Context ctx = new StandardContext();
ctx.setPath("/myApp");
ctx.setDocBase("/myApp");

但是如果所有的tomcat组件都这样硬编码,调整组件配置或属性值都必须要重新编译,采用digester库解析XML配置文件,xml文件中的每个元素都会转换为一个java对象,元素的属性用于设置java对象的属性,这样就可以通过编辑xml文件来修改tomcat配置而不用去重新编译项目代码;比如上面的代码可以转换为下面的配置:

<context docBase="/myApp" path="/myApp" />

基本用法:

1、digester库解析XML时定义了pattern和Rule,XML文档的根元素的pattern为元素名称,子元素的pattern为父元素的pattern + “/” + 子元素的名称;一条Rule(规则)指定了当Digester遇到这个pattern时要执行的一个或多个动作,Rule都存储在由Rules接口表示的一类存储器中;另外Digester解析XML文档时,遇到pattern匹配的开始标签时,他会调用Rule对象的begin方法,而当遇到pattern的结束标签时,他会调用Rule对象的end方法;

如下面的XML文档:

Employee节点的pattern为“employee”,office节点的pattern为“employee/office”,address节点的pattern为“employee/office/address”;

2、创建对象:

若想要Digester在遇到某个pattern时创建对象,则需要调用addObjectCreate()方法,如:

digester.addObjectCreate("employee",cn.com.digesterTest.Employee.class);

或者digester.addObjectCreate("employee", "cn.com.digesterTest.Employee");

或者digester.addObjectCreate("employee", "cn.com.digesterTest.Employee", "className");

其定义原型为:

3、设置属性:

addSetProperties可以使Digester对象为创建的对象设置属性,会将XML文档中的属性名称与对象中的对应属性对应起来,分别调用其对应的set方法设置属性值,如果对象中没有XML文档中定义的属性名称则会发生错误,addSetProperties定义原型如下:

使用示例如下:

digester.addSetProperties("employee");

这个Rule会将xml文档的employee节点的属性值都设置到内部栈最顶端对象的对应属性值里面去;

4、调用方法:

Digester类的addCallMethod方法能添加一条Rule,使得Digester在遇到与该Rule相关联的模式时调用内部栈最顶端对象的某个方法,定义原型如下:

5、创建对象之间的关系:

Digester每根据XML元素创建一个对象都会压入一个内部栈中,如果想将后面一个对象作为参数传入第一个对象的某个方法时,可以调用addSetNext方法来指定这个对象之间的关系,定义原型如下:

Pattern参数是后面一个对象的pattern路径,应该具有下面的格式:

firstObject/secondObject

methodName参数是前面一个对象要调用的方法名称;

digester.addObjectCreate("employee","cn.com.digesterTest.Employee");

digester.addObjectCreate("employee/office","cn.com.digesterTest.Office");

digester.addSetNext("employee/office", "addOffice");

其中addOffice定义于Employee类中,该方法接收一个Office对象作为参数;

6、验证XML文档:

Digester对象的validating属性指明了是否要对XML文档进行有效性验证,默认值为false,可以通过setValidating来设置是否要对xml文档进行有效性验证:

7、使用RuleSet:

Rule对象集合是RuleSet接口的实例,在创建了Digester对象后,可以创建一个RuleSet对象,并调用addRuleSet方法将其添加到Digester对象中。该接口定义了两个方法:

public String getNamespaceURI();

public void addRuleInstances(Digester digester);

getNamespaceURI方法返回将要应用在RuleSet中所有Rule对象的命名空间的URI,addRuleInstances方法将在当前RuleSet中的Rule对象的集合作为该方法的参数添加到digester实例中。

RuleSetBase类是实现RuleSet接口的一个抽象类,提供了getNamespaceURI的默认实现,自定义的RuleSet只需要从RuleSetBase派生过来并实现addRuleInstances方法即可。

比如实现自定义的RuleSet如下:

然后可以调用Digester.addRuleSet(new EmployeeRuleSet())来指定Rule集合;

8、Tomcat中Catalina.java中对Digester的一个用法:

  • 首先在创建Digester对象时将Catalina对象压入堆栈:

  • 然后在解析顶层元素时,将顶层元素创建的对象与Catalina对象关联:

第一条规则表明在遇到server元素时要创建Standardserver类的实例并压入内部堆栈,第二条规则指明要对Server对象的指定属性名设置同名的属性值;第三条规则将Server对象与内部栈中的栈底元素相关联,刚才看到已经Catalina对象压入栈底,因此第三条规则会将Server对象通过调用Catalina.setServer方法设置为Catalina对象的Server属性;

UML图:

1、Digester的实现基于了SAX,SAX是一个比较有名的xml解析器,但是SAX提供的功能比较底层,我们在平时写代码如果xml配置文件写错了,经常会抛SAXParseException,SAX是基于事件驱动的,当读到一个xml配置文件的起始标签或者结束标签的时候就会触发一个事件,然后调用一个 Handler回调函数。Digester就是扩展了这一点。Digester继承了SAX的DefaultHandler类,重写了这个Handler的一些回调方法。

Digester的通用性就是靠用户在解析自定义xml文件时指定自定义rule来完成的。这个rule就是当SAX解析到一些标签的时候触发Digester 的handler函数所用到的一些处理规则,在handler函数里会去扫描到相应的规则来完成对象的构建工作。

2、Rule类作为所有规则的抽象基类,不同的规则类从Rule类派生过来,如果要实现自定义规则,也需要从Rule类派生过来;上面讲的addObjectCreate、addCallMethod、addSetNext等方法均是先创建Rule实例并添加到Rules中,如下:

Rule类有两个重要方法,begin和end,在解析到XML文档的pattern标签开始处时,调用begin方法,解析到pattern标签的结束处时,调用end方法,ObjectCreateRule类的begin和end方法代码如下:

begin方法根据默认的类名和指定要读取XML属性的类名获取最终的类名realClassName,根据类名生成实例对象并压入内部栈中;

end方法时只是将实例对象从内部栈中弹出,表示XML已经解析到标签的结束处,此时该对象不再使用了,可以从内部栈中弹出;

3、Rules接口表示Rule的集合,当在Digester中调用addRule时,其实是将Rule对象添加到Rules集合中了:

可以看出Rules对象是Digester类的一个成员变量,并且是在第一次访问时才创建的RulesBase实例;

4、为了代码简洁性,可以将添加规则Rule的代码集中到RuleSet对象中,然后将RuleSet对象通过addRuleSet方法添加到Digester的Rules集合中,实现自定义RuleSet时需要先从RuleSetBase类派生过来,然后重新实现他的addRuleInstances方法;

Digester库使用总结的更多相关文章

  1. How tomcat works 读书笔记十五 Digester库 下

    在这一节里我们说说ContextConfig这个类. 这个类在很早的时候我们就已经使用了(之前那个叫SimpleContextConfig),但是在之前它干的事情都很简单,就是吧context里的co ...

  2. How tomcat works 读书笔记十五 Digester库 上

    Digester库 在前面的几个章节里,我们对tomcat里各个组件的配置完全是使用写硬编码的形式完成的. 如 Context context = new StandardContext(); Loa ...

  3. Digester库

    在之前所学习关于启动简单的Tomcat部分实现的代码中,我们使用一个启动类Bootstrap类 来实例化连接器.servlet容器.wrapper实例.和其他组件,然后调用各个对象的set方法将他们关 ...

  4. How Tomcat Works(十八)

    在前面的文章中,如果我们要启动tomcat容器,我们需要使用Bootstrap类来实例化连接器.servlet容器.Wrapper实例和其他组件,然后调用各个对象的set方法将它们关联起来:这种配置应 ...

  5. Struts2技术内幕 读书笔记三 表示层的困惑

    表示层能有什么疑惑?很简单,我们暂时忘记所有的框架,就写一个注册的servlet来看看. index.jsp <form id="form1" name="form ...

  6. tomcat源码阅读之集群

    一. 配置: 在tomcat目录下的conf/Server.xml配置文件中增加如下配置: <!-- Cluster(集群,族) 节点,如果你要配置tomcat集群,则需要使用此节点. clas ...

  7. Tomcat 源码分析(转)

    本文转自:http://blog.csdn.net/haitao111313/article/category/1179996 Tomcat源码分析(一)--服务启动 1. Tomcat主要有两个组件 ...

  8. 常用Java开源库(新手必看)

    Jakarta common: Commons LoggingJakarta Commons Logging (JCL)提供的是一个日志(Log)接口(interface),同时兼顾轻量级和不依赖于具 ...

  9. Tomcat组件梳理—Digester的使用

    Tomcat组件梳理-Digester的使用 再吐槽一下,本来以为可以不用再开一个篇章来梳理Digester了,但是发现在研究Service的创建时,还是对Digester的很多接口或者机制不熟悉,简 ...

随机推荐

  1. python-day34--进程补充

    一.进程补充: 1,生产者消费者模型: 两类角色,一类负责生产数据,另外那类负责数据 生产完放到共享空间,另外那类到空间取数据进行处理 好处: 生产数据的同时可以进行数据的处理,不用等(并发效果) 问 ...

  2. 如何合理命名CSS文件——摘自网友

    有经验的网页制作者都明白,对于有多个栏目的大型网站而言,使用单一的CSS文件是不可能的.但CSS文件名如何命名对于新手来说是件容易出乱子的事.如何才能将CSS的命名做得井井有条? 坚持使用统一的CSS ...

  3. python中字符串连接的四种方式

    以下实例展示了join()的使用方法 #!/usr/bin/python str = "-"; seq = ("a", "b", " ...

  4. learning ext2 filesystem notes

    reference:  http://e2fsprogs.sourceforge.net/ext2intro.html reference: http://www.nongnu.org/ext2-do ...

  5. js获得焦点和失去焦点那些事

    <!doctype html> <html> <head> <meta charset="utf-8"> <meta name ...

  6. cocos2d-x安装教程

    cocos2d-x安装教程 cocos的安装方法有多种,今天讲的是其中一种,使用cocos的源代码直接进行编译. 下载cocos2d-x的源代码,提供两种方式给大家 -- 中文官网下载 -- 英文官网 ...

  7. Entity Framework之犹豫不决

    记得去年初就开始关注Entity Framework,那时只是简单测试了一下,发现较之Nhibernate不太成熟.当时的EF主要表驱动方式开发,过度依赖edm文件,并且数据层耦合了模型层,让一些MV ...

  8. 练习vue(用户管理)1

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  9. python函数def

    #函数就是实现一个特定功能的程序块 #下面这个函数实现了打印helloworld的功能 def print_hello(): print('hello world!') #这是调用方法 print_h ...

  10. 关于apicloud ios自定义模块引用第三方framework not found for architecture armv7

    1 .自定义模块 新建模块必须是静态库 2.使用的第三方framework 必须要把 .h文件开放出来 3.编译要用 真机模式 (上传模块以后,自定义load要编译,用生成的二维码调试) 4. 添加监 ...