Tomcat 8(八)Tomcat解析server.xml的工具—Digester

本文介绍了Tomcat如何利用Apache的Digester项目解析server.xml配置文件。内容涉及 Digester的使用,包括依赖的jar包,解析过程以及在Tomcat中的具体应用。在Tomcat的Catalina类的load方法中,通过创建Digester实例并设置规则,读取并解析server.xml。解析过程分为创建Digester、读取XML文件和解析文件三个步骤。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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

<?xml version='1.0' encoding='utf-8'?>
<School name="CSDN">
	<Grade name="1">
		<Class name="1" number="31"/>
		<Class name="2" number="32"/>
	</Grade>
	<Grade name="2">
		<Class name="1" number="41"/>
		<Class name="2" number="42"/>
	</Grade>
</School>

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

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

School.java

package digester;

public class School {
	private String name;
	private Grade grades[] = new Grade[0];
	private final Object servicesLock = new Object();
	
	public void addGrade(Grade g){
		synchronized (servicesLock) {
			Grade results[] = new Grade[grades.length + 1];
            System.arraycopy(grades, 0, results, 0, grades.length);
            results[grades.length] = g;
            grades = results;
        }
	}
	
	public Grade[] getGrades() {
		return grades;
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

}

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

Grade.java

package digester;

public class Grade {
	private String name;
	private Class classes[] = new Class[0];
	private final Object servicesLock = new Object();
	
	public void addClass(Class c){
		synchronized (servicesLock) {
			Class results[] = new Class[classes.length + 1];
            System.arraycopy(classes, 0, results, 0, classes.length);
            results[classes.length] = c;
            classes = results;
        }
	}
	
	public Class[] getClasses() {
		return classes;
	}
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
}

Class.java

package digester;

public class Class {
	private String name;
	private int number;
	
	public String getName() {
		return name;
	}
	
	public void setName(String name) {
		this.name = name;
	}
	
	public int getNumber() {
		return number;
	}
	
	public void setNumber(int number) {
		this.number = number;
	}
	
}

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

package digester;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;

import org.apache.tomcat.util.digester.Digester;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class DigesterTest {
	private School school;
	
	public School getSchool() {
		return school;
	}

	public void setSchool(School s) {
		this.school = s;
	}

	public void digester() throws IOException, SAXException{
		//读取School.xml
		File file = new File("D:\\School.xml");
		InputStream inputStream = new FileInputStream(file);
		InputSource inputSource = new InputSource(file.toURI().toURL().toString());;
		inputSource.setByteStream(inputStream);
		//创建Digester
	    Digester digester = new Digester();
	    //是否需要用DTD验证XML文档的合法性
	    digester.setValidating(false);
	    //将当前对象放到对象堆的最顶层
	    digester.push(this);
	    
	    /* 下面开始为Digester创建匹配规则
	     * 在Digester内School、School/Grade、School/Grade/Class
	     * 分别对应School.xml的School、Grade、Class节点
	     */
	    
	    //为School创建规则
	    /*
	     * Digester.addObjectCreate(String pattern, String className, String attributeName)
	     * pattern--匹配的节点
	     * className--该节点对应的默认实体类
	     * attributeName--如果该节点有className属性,用className的值替换默认实体类
	     * Digester匹配到School节点,如果School节点没有className属性,将创建digester.School对象;如果School节点有className属性,将创建指定的(className属性的值)对象
	    */
	    digester.addObjectCreate("School",
                "digester.School",
                "className");
	    //将指定节点的属性映射到对象,即将School节点的name的属性映射到School.java
	    digester.addSetProperties("School");
	    /*
	     * Digester.addSetNext(String pattern, String methodName, String paramType)
	     * pattern--匹配的节点
	     * methodName--调用父节点的方法
	     * paramType--父节点的方法接收的参数类型
	     * Digester匹配到School节点,将调用DigesterTest(School的父节点)的setSchool方法,参数为School对象
	     */
	    digester.addSetNext("School",
           "setSchool",
           "digester.School");
	    
	    //为School/Grade创建规则
	    digester.addObjectCreate("School/Grade",
                "digester.Grade",
                "className");
	    digester.addSetProperties("School/Grade");
	    //Grade的父节点为School
	    digester.addSetNext("School/Grade",
           "addGrade",
           "digester.Grade");
	    
	    //为School/Grade/Class创建规则
	    digester.addObjectCreate("School/Grade/Class",
                "digester.Class",
                "className");
	    digester.addSetProperties("School/Grade/Class");
	    digester.addSetNext("School/Grade/Class",
           "addClass",
           "digester.Class");
	    digester.parse(inputSource);
	}
	
	//打印School信息
	public void print(School s){
		if(s!=null){
			System.out.println(s.getName() + "有" + s.getGrades().length + "个年级");
			for(int i=0;i<s.getGrades().length;i++){
				if(s.getGrades()[i] !=null){
					Grade g = s.getGrades()[i];
					System.out.println(g.getName() + "年级 有 " + g.getClasses().length + "个班:");
					for(int j=0;j<g.getClasses().length;j++){
						if(g.getClasses()[j] !=null){
							Class c = g.getClasses()[j];
							System.out.println(c.getName() + "班有" + c.getNumber() + "人");
						}
					}
				}
			}
		}
	}
	
	public static void main(String[] args) throws IOException, SAXException {
		DigesterTest digesterTest = new DigesterTest();
		digesterTest.digester();
		digesterTest.print(digesterTest.school);
	}
}

DigesterTest的输出:

CSDN有2个年级
1年级 有 2个班:
1班有31人
2班有32人
2年级 有 2个班:
1班有41人
2班有42人

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

1. 创建Digester并设置规则

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

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

protected Digester createStartDigester() {
        Digester digester = new Digester();
        digester.setValidating(false);
        digester.setRulesValidation(true);
        HashMap<Class<?>, List<String>> fakeAttributes = new HashMap<>();
        ArrayList<String> attrs = new ArrayList<>();
        attrs.add("className");
        fakeAttributes.put(Object.class, attrs);
        digester.setFakeAttributes(fakeAttributes);
        digester.setUseContextClassLoader(true);

        digester.addObjectCreate("Server",
                                 "org.apache.catalina.core.StandardServer",
                                 "className");
        digester.addSetProperties("Server");
        //父节点为Catalina
		digester.addSetNext("Server",
                            "setServer",
                            "org.apache.catalina.Server");

        digester.addObjectCreate("Server/Service",
                                 "org.apache.catalina.core.StandardService",
                                 "className");
        digester.addSetProperties("Server/Service");
		//父节点为Server
        digester.addSetNext("Server/Service",
                            "addService",
                            "org.apache.catalina.Service");
		//为Connector节点创建规则
        digester.addRule("Server/Service/Connector",
                         new ConnectorCreateRule());

        /*
		 * 如果某个节点包含的规则比较多,可以为该节点创建一个规则类
		 * 执行digester.addRuleSet(new EngineRuleSet("Server/Service/")) 
		 * 可以将EngineRuleSet内包含的规则,添加到当前digester中
		 */
        digester.addRuleSet(new EngineRuleSet("Server/Service/"));
		//为Cluster节点创建规则
        addClusterRuleSet(digester, "Server/Service/Engine/Host/Cluster/");
    }

2. 读取server.xml文件

InputSource inputSource = null;
        InputStream inputStream = null;
        File file = null;
        try {
            file = configFile();
            inputStream = new FileInputStream(file);
            inputSource = new InputSource(file.toURI().toURL().toString());
        } catch (Exception e) {
            if (log.isDebugEnabled()) {
                log.debug(sm.getString("catalina.configFail", file), e);
            }
        }

3. 利用Digester解析xml文件

try {
            inputSource.setByteStream(inputStream);
            digester.push(this);
            digester.parse(inputSource);
        } catch (SAXParseException spe) {
            log.warn("Catalina.start using " + getConfigFile() + ": " +
                    spe.getMessage());
            return;
        } catch (Exception e) {
            log.warn("Catalina.start using " + getConfigFile() + ": " , e);
            return;
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                // Ignore
            }
        }


参考文章:

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

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

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值