How Tomcat work 之第十五章之Digester

来源:互联网 发布:react.js控制 隐藏div 编辑:程序博客网 时间:2024/04/30 07:38

回顾


我们已经在前面的章节中看到了,使用一个Bootstrap类实例化一个connector,一个context,wrappers,和其他组件。只要有了这些对象,就可通过调用不同对象的set方法使彼此关联起来。比如,为了实例化一个connector和一个context,使用如下代码:


Connector connector = new HttpConnector();

Context context = new StandardContext();


为了将connector与context关联起来,就写如下代码:


connector.setContainer(context);


你也可以通过调用对应的set方法配置每个对象的属性。例如,通过调用setPath和setDocBase方法可以设置一个Context对象的path属性和docBase属性。


context.setPath("/myApp");

context.setDocBase("/myApp");


另外,通过实例化不同的组件和调用context对应的add方法将不同的组件添加到Context对象上。例如,下面是如下添加一个lifecycle监听器和一个加载器到你的Context对象上。


LifecycleListener listener = new SimpleContextConfig();

((Lifecycle) context).addLifecycleListener(listener);

Loader loader = new WebappLoader();

context.setLoader(loader);


一旦所有必需关联和附件都执行就绪了,就调用connector的initialize和start方法和Context的start方法来启动应用程序。


connector.initialize();

((Lifecycle) connector).start ();

((Lifecycle) context).start();



这种应用程序的配置有一个明显的缺陷:每个都是硬编码。改变一个组件或者甚至是一个属性的值需要Bootstrap类重新编译。最终,Tomcat的设计者选择了一种更优雅的配置方式即:叫做server.xml的XML文档。server.xml中的每个元素可以转化为一个Java对象并且一个元素的属性用作设置一个属性。这样,你仅仅简单编辑server.xml文件来改变Tomcat设置。例如,一个server.xml文件中的Context元素表示一个Context:


<context/>


为设置path和docBase属性,你可以在xml中使用如下元素:


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


Tomcat使用开源包Digester将XML元素转为Java对象。


下一节中演示了 一个web应用的配置。一个context表示一个Web应用程序,因此通过安装已经实例化的Context实例来获取一个web应用的配置。用于配置一个web应用的xml文件叫做web.xml。这个问价必须置于这个应用程序的WEB-INF目录下。


Digester是Apache下的一个开源项目。你可以从一下url下载:http://jakarta.apache.org/commons/digester/。这个Digester API有三个包,都在commons-Digester.jar文件中。

         

    1  org.apache.commons.digester 这个包可以处理基于规则的任何xml文档

    2  org.apache.commons.digester.rss.  解析xml文档的Digester的例子使用。

    3  org.apache.commons.digester.xmlrules。这个包提供了Digester的基于XML定义的规则。



我们不会使用这个包中提供的所有。相反,我们仅仅演示Tomcat使用的几类比较重要的。这次我们将以演示Digester类开始,这是Digester包中最重要的类。



the Digester class


org.apache.commons.digester.Digester类是Digester包中的主要类。你使用它解析一个xml文档。对于文档中的每个元素,Digester对象将检查是否需要做点什么。作为开发者将决定在调用其parse方法前,Digester实例必须要做的什么。



当Digester对象碰到一个XML元素的时候,如何告诉其要做什么呢?很简单。你定义模式并且用一个或者更多的规则来关联每个模式。在一个XML文档中的root元素有一个模式,其与这个元素的名字一模一样。例如,代码清单15.1显示一样:


Listing 15.1: The example.xml file


<?xml version="1.0" encoding="ISO-8859-1"?><employee firstName="Brian" lastName="May">     <office>              <address streeName="Wellington Street" streetNumber="110"/>     </office></employee>



这个XML文档的根元素师employee。这个元素有这样的模式employee。office元素是employee元素的子元素。子元素的模式是子元素的名字加上它的包含元素employee加上“ /”作为前缀。因此,office元素的的模式是employee/office.address元素的模式即:


   父元素的模式+“/”这个元素的名字


这个地址元素的父元素是<office>。其模式是employee/office。因此,<address>的模式是employee/office/address。


现在你明白了一个模式是如何从一个xml文档中的导出的,接下来来讨论一下规则。


当 遇到一个唯一的模式的时候,一个规则指定了一个或者一组动作,这些都会Digester必须做的。rule由org.apache.commons.digester.Rule类。Digester类有一个或者多个Rule对象。在一个Digester实例中,这些规则和对应的模式存放在这样的类型中,由org.apache.commons.digester.Rules接口表示。每次向Digester实例中添加一个规则的时候,Rule对象也要添加到Rules对象中。


除此之外,Rule类还有begin和end方法,当解析一个xml文档的时候并且遇到配位模式的start元素的时候,Digester实例调用添加到它的Rule对象的begin方法。当Digester实例遇到一个end元素的时候调用Rule对象的end方法。



当解析清单15.1的example.xml文档的时候,以下是Digester对象做的:


            1   它首先遇到以employee 开始的元素,因此检查是否有模式employee的规则。如果有,Digester执行Rule对象的begin方法,以第一个添加到这个Digester的begin方法开始。

            2  之后遇到了以office 开始的元素,因此Digester对象检查是否有employee/office模式的规则。如果有,执行实现了rule的begin方法。

            3  下一步,Digester实例遇到了以address开始的元素。检查是否有employee/office/address模式的规则。如果有,执行rule的begin方法。

            4  下一步,Digester实例遇到以address结束的元素,调用匹配规则的end方法

            5 下一步,Digester实例遇到以office结束的元素,运行匹配规则的end方法。

            6 最终,Digester实例遇到以employee结束的元素,执行匹配规则的end方法。


你可以使用什么元素了?Digester已经预先定义了大量的规则。甚至不必理解这些Rule类你也可以使用这些规则。然而,如果这些规则不够用,也可以定义自己的规则。预先定义的规则包含了创建对象,设置属性值等等。


创建对象--create objects


如果你想你的Digester实例对一个指定的模式创建一个对象,调用addObjectCreate方法。这个方法有四个重载。其中两个用的最频繁的方法签名如下:


public void addObjectCreate(java.lang.String pattern,java.lang.Class clazz);


public void addObjectCreate(java.lang.String pattern,java.lang.String className);



你传递了模式和一个类对象或者一个类名。例如,当遇到模式employee时,如果你想让Digester实例创建一个Employee对象(见ex15.pyrmont.digestertest.Employee),只需要调用下面代码中的一行。


digester.addObjectCreate("employee",ex15.pyrmont.digestertest.Employee.class);

或者

digester.addObjectCreate("employee","ex15.pyrmont.digestertest.Employee");


其他的两个addObjectCreate重载方法允许你在xml元素中定义类名,作为方法中传递参数。这是一个非常强大的功能,因为类名可以在运行时决定。下面是这两种方法的签名:


public void addObjectCreate(java.lang.String pattern,java.lang.String className, java.lang.String attributeName)


public void addObjectCreate(java.lang.String pattern,java.lang.String attributeName, java.lang.Class clazz)



在这两个重载方法中,attributeName参数指定了这个XML元素的属性名,包含了需要实例化的类名。例如,你可以使用如下代码添加一个规则来创建一个对象。


digester.addObjectCreate("employee", null, "className");


这里属性名是className。


稍后传递XML元素中的类名。


<employee firstName="Brian" lastName="May" className="ex15.pyrmont.digestertest.Employee">


或者,你可以在addObjectCreate方法中定义默认的类名:


digester.addObjectCreate("employee","ex15.pyrmont.digestertest.Employee", "className");



如果employee元素包含了一个className属性,被这个属性指定的值将用作类名来实例化。如果没有属性名,就用默认的。


由addObjectCreate方法创建的对象被放入一个内部栈中。也提供了大量的方法来peek,push和pop这个创建的对象。






0 0