先码后看 Tomcat是怎么启动容器的——Digester篇 侵立删

来源:互联网 发布:二手手机平台 知乎 编辑:程序博客网 时间:2024/06/05 01:57

转自:http://blog.csdn.net/flyliuweisky547/article/details/23872231


Tomcat是利用Digester解析server.xmlDigesterApache下的开源项目

Digester官网:http://commons.apache.org/proper/commons-digester/

使用Digester,需要依赖一些jar包。Digester依赖的jar包可以从网上下载,也可以使用Tomcat提供的jar

方案一:从网上下载jar

commons-beanutils.jar

commons-digester.jar

commons-logging.jar

commons-collections.jar(下载commons-collections-3。commons-collections-4commons-collections的package命名由org.apache.commons.collections改为org.apache.commons.collections4,而Digester内部仍按org.apache.commons.collections使用的)

方案二:使用Tomcat目录下的jar包

tomcat-juli.jar($CATALINA_HOME\bin)

tomcat-util.jar($CATALINA_HOME\lib)

tomcat-util-scan.jar($CATALINA_HOME\lib)

本文采用方案一

下面来看看Digester如何解析School.xml

[html] view plain copy
  1. <?xml version='1.0' encoding='utf-8'?>  
  2. <School name="CSDN">  
  3.     <Grade name="1">  
  4.         <Class name="1" number="31"/>  
  5.         <Class name="2" number="32"/>  
  6.     </Grade>  
  7.     <Grade name="2">  
  8.         <Class name="1" number="41"/>  
  9.         <Class name="2" number="42"/>  
  10.     </Grade>  
  11. </School>  

School是School.xml的最顶层节点,School节点下包含Grade节点,Grade节点下包含Class节点。(学校下有两个年级,每个年级下有两个班级,班级下的number表示人数)

首先要创建与School.xml中各个节点对应的实体类School.java、Grade.java、Class.java(这些类都放在digester包下)

School.java

[java] view plain copy
  1. package digester;  
  2.   
  3. public class School {  
  4.     private String name;  
  5.     private Grade grades[] = new Grade[0];  
  6.     private final Object servicesLock = new Object();  
  7.       
  8.     public void addGrade(Grade g){  
  9.         synchronized (servicesLock) {  
  10.             Grade results[] = new Grade[grades.length + 1];  
  11.             System.arraycopy(grades, 0, results, 0, grades.length);  
  12.             results[grades.length] = g;  
  13.             grades = results;  
  14.         }  
  15.     }  
  16.       
  17.     public Grade[] getGrades() {  
  18.         return grades;  
  19.     }  
  20.       
  21.     public String getName() {  
  22.         return name;  
  23.     }  
  24.   
  25.     public void setName(String name) {  
  26.         this.name = name;  
  27.     }  
  28.   
  29. }  

School里的Grade数组用来存放School包含的Grade。调用School. addGrade(Grade g),可以往Grade数组添加Grade

Grade.java

[java] view plain copy
  1. package digester;  
  2.   
  3. public class Grade {  
  4.     private String name;  
  5.     private Class classes[] = new Class[0];  
  6.     private final Object servicesLock = new Object();  
  7.       
  8.     public void addClass(Class c){  
  9.         synchronized (servicesLock) {  
  10.             Class results[] = new Class[classes.length + 1];  
  11.             System.arraycopy(classes, 0, results, 0, classes.length);  
  12.             results[classes.length] = c;  
  13.             classes = results;  
  14.         }  
  15.     }  
  16.       
  17.     public Class[] getClasses() {  
  18.         return classes;  
  19.     }  
  20.       
  21.     public String getName() {  
  22.         return name;  
  23.     }  
  24.       
  25.     public void setName(String name) {  
  26.         this.name = name;  
  27.     }  
  28.       
  29. }  

Class.java

[java] view plain copy
  1. package digester;  
  2.   
  3. public class Class {  
  4.     private String name;  
  5.     private int number;  
  6.       
  7.     public String getName() {  
  8.         return name;  
  9.     }  
  10.       
  11.     public void setName(String name) {  
  12.         this.name = name;  
  13.     }  
  14.       
  15.     public int getNumber() {  
  16.         return number;  
  17.     }  
  18.       
  19.     public void setNumber(int number) {  
  20.         this.number = number;  
  21.     }  
  22.       
  23. }  

然后创建测试类DigesterTest.java。DigesterTest.java的digester方法用来读取School.xml、创建Digester并设置规则、解析School.xml;print方法用来打印School的信息

[java] view plain copy
  1. package digester;  
  2.   
  3. import java.io.File;  
  4. import java.io.FileInputStream;  
  5. import java.io.IOException;  
  6. import java.io.InputStream;  
  7.   
  8. import org.apache.tomcat.util.digester.Digester;  
  9. import org.xml.sax.InputSource;  
  10. import org.xml.sax.SAXException;  
  11.   
  12. public class DigesterTest {  
  13.     private School school;  
  14.       
  15.     public School getSchool() {  
  16.         return school;  
  17.     }  
  18.   
  19.     public void setSchool(School s) {  
  20.         this.school = s;  
  21.     }  
  22.   
  23.     public void digester() throws IOException, SAXException{  
  24.         //读取School.xml  
  25.         File file = new File("D:\\School.xml");  
  26.         InputStream inputStream = new FileInputStream(file);  
  27.         InputSource inputSource = new InputSource(file.toURI().toURL().toString());;  
  28.         inputSource.setByteStream(inputStream);  
  29.         //创建Digester  
  30.         Digester digester = new Digester();  
  31.         //是否需要用DTD验证XML文档的合法性  
  32.         digester.setValidating(false);  
  33.         //将当前对象放到对象堆的最顶层  
  34.         digester.push(this);  
  35.           
  36.         /* 下面开始为Digester创建匹配规则 
  37.          * 在Digester内School、School/Grade、School/Grade/Class 
  38.          * 分别对应School.xml的School、Grade、Class节点 
  39.          */  
  40.           
  41.         //为School创建规则  
  42.         /* 
  43.          * Digester.addObjectCreate(String pattern, String className, String attributeName) 
  44.          * pattern--匹配的节点 
  45.          * className--该节点对应的默认实体类 
  46.          * attributeName--如果该节点有className属性,用className的值替换默认实体类 
  47.          * Digester匹配到School节点,如果School节点没有className属性,将创建digester.School对象;如果School节点有className属性,将创建指定的(className属性的值)对象 
  48.         */  
  49.         digester.addObjectCreate("School",  
  50.                 "digester.School",  
  51.                 "className");  
  52.         //将指定节点的属性映射到对象,即将School节点的name的属性映射到School.java  
  53.         digester.addSetProperties("School");  
  54.         /* 
  55.          * Digester.addSetNext(String pattern, String methodName, String paramType) 
  56.          * pattern--匹配的节点 
  57.          * methodName--调用父节点的方法 
  58.          * paramType--父节点的方法接收的参数类型 
  59.          * Digester匹配到School节点,将调用DigesterTest(School的父节点)的setSchool方法,参数为School对象 
  60.          */  
  61.         digester.addSetNext("School",  
  62.            "setSchool",  
  63.            "digester.School");  
  64.           
  65.         //为School/Grade创建规则  
  66.         digester.addObjectCreate("School/Grade",  
  67.                 "digester.Grade",  
  68.                 "className");  
  69.         digester.addSetProperties("School/Grade");  
  70.         //Grade的父节点为School  
  71.         digester.addSetNext("School/Grade",  
  72.            "addGrade",  
  73.            "digester.Grade");  
  74.           
  75.         //为School/Grade/Class创建规则  
  76.         digester.addObjectCreate("School/Grade/Class",  
  77.                 "digester.Class",  
  78.                 "className");  
  79.         digester.addSetProperties("School/Grade/Class");  
  80.         digester.addSetNext("School/Grade/Class",  
  81.            "addClass",  
  82.            "digester.Class");  
  83.         digester.parse(inputSource);  
  84.     }  
  85.       
  86.     //打印School信息  
  87.     public void print(School s){  
  88.         if(s!=null){  
  89.             System.out.println(s.getName() + "有" + s.getGrades().length + "个年级");  
  90.             for(int i=0;i<s.getGrades().length;i++){  
  91.                 if(s.getGrades()[i] !=null){  
  92.                     Grade g = s.getGrades()[i];  
  93.                     System.out.println(g.getName() + "年级 有 " + g.getClasses().length + "个班:");  
  94.                     for(int j=0;j<g.getClasses().length;j++){  
  95.                         if(g.getClasses()[j] !=null){  
  96.                             Class c = g.getClasses()[j];  
  97.                             System.out.println(c.getName() + "班有" + c.getNumber() + "人");  
  98.                         }  
  99.                     }  
  100.                 }  
  101.             }  
  102.         }  
  103.     }  
  104.       
  105.     public static void main(String[] args) throws IOException, SAXException {  
  106.         DigesterTest digesterTest = new DigesterTest();  
  107.         digesterTest.digester();  
  108.         digesterTest.print(digesterTest.school);  
  109.     }  
  110. }  

DigesterTest的输出:

[plain] view plain copy
  1. CSDN有2个年级  
  2. 1年级 有 2个班:  
  3. 1班有31人  
  4. 2班有32人  
  5. 2年级 有 2个班:  
  6. 1班有41人  
  7. 2班有42人  

Tomcat解析server.xml是在Catalinaload方法内进行的。load方法可以划分成三步:

1. 创建Digester并设置规则

load方法内通过Digester digester = createStartDigester()创建Digester 并设置规则。createStartDigester也是Catalina内的方法

createStartDigester方法的内容(为了简介,每种创建规则的方式各列一个)

[java] view plain copy
  1. protected Digester createStartDigester() {  
  2.         Digester digester = new Digester();  
  3.         digester.setValidating(false);  
  4.         digester.setRulesValidation(true);  
  5.         HashMap<Class<?>, List<String>> fakeAttributes = new HashMap<>();  
  6.         ArrayList<String> attrs = new ArrayList<>();  
  7.         attrs.add("className");  
  8.         fakeAttributes.put(Object.class, attrs);  
  9.         digester.setFakeAttributes(fakeAttributes);  
  10.         digester.setUseContextClassLoader(true);  
  11.   
  12.         digester.addObjectCreate("Server",  
  13.                                  "org.apache.catalina.core.StandardServer",  
  14.                                  "className");  
  15.         digester.addSetProperties("Server");  
  16.         //父节点为Catalina  
  17.         digester.addSetNext("Server",  
  18.                             "setServer",  
  19.                             "org.apache.catalina.Server");  
  20.   
  21.         digester.addObjectCreate("Server/Service",  
  22.                                  "org.apache.catalina.core.StandardService",  
  23.                                  "className");  
  24.         digester.addSetProperties("Server/Service");  
  25.         //父节点为Server  
  26.         digester.addSetNext("Server/Service",  
  27.                             "addService",  
  28.                             "org.apache.catalina.Service");  
  29.         //为Connector节点创建规则  
  30.         digester.addRule("Server/Service/Connector",  
  31.                          new ConnectorCreateRule());  
  32.   
  33.         /* 
  34.          * 如果某个节点包含的规则比较多,可以为该节点创建一个规则类 
  35.          * 执行digester.addRuleSet(new EngineRuleSet("Server/Service/"))  
  36.          * 可以将EngineRuleSet内包含的规则,添加到当前digester中 
  37.          */  
  38.         digester.addRuleSet(new EngineRuleSet("Server/Service/"));  
  39.         //为Cluster节点创建规则  
  40.         addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");  
  41.     }  

2. 读取server.xml文件

[java] view plain copy
  1. InputSource inputSource = null;  
  2.         InputStream inputStream = null;  
  3.         File file = null;  
  4.         try {  
  5.             file = configFile();  
  6.             inputStream = new FileInputStream(file);  
  7.             inputSource = new InputSource(file.toURI().toURL().toString());  
  8.         } catch (Exception e) {  
  9.             if (log.isDebugEnabled()) {  
  10.                 log.debug(sm.getString("catalina.configFail", file), e);  
  11.             }  
  12.         }  

3. 利用Digester解析xml文件

[java] view plain copy
  1. try {  
  2.             inputSource.setByteStream(inputStream);  
  3.             digester.push(this);  
  4.             digester.parse(inputSource);  
  5.         } catch (SAXParseException spe) {  
  6.             log.warn("Catalina.start using " + getConfigFile() + ": " +  
  7.                     spe.getMessage());  
  8.             return;  
  9.         } catch (Exception e) {  
  10.             log.warn("Catalina.start using " + getConfigFile() + ": " , e);  
  11.             return;  
  12.         } finally {  
  13.             try {  
  14.                 inputStream.close();  
  15.             } catch (IOException e) {  
  16.                 // Ignore  
  17.             }  
  18.         }  


参考文章:

http://blog.csdn.net/caihaijiang/article/details/5944955

http://www.cnblogs.com/bjzhanghao/archive/2005/03/25/125747.html

阅读全文
0 0
原创粉丝点击