TOMCAT底層解析server.xml使用。
Dom4j是把一個xml文件全部讀取到內存中,構建成一個DOM樹來解析,所以Dom4j適合讀取比較小的xml文件。
SAX是基於文件流來解析xml文件的,在讀取xml文件流時,SAX會通過節點來觸發相應的操作,也可以說SAX是基於文件流的事情觸發機制來解析xml文件的。
Digeter是apache的common項目,作用是將XML轉化成對象,使用者直接從對象中獲取xml的節點信息。Digester是對SAX的包裝,它也是基於文件流來解析xml文件,只不過這些解析操作對用戶是透明的。Tomcat的配置文件conf/server.xml就是用Digester來讀取的。
一般用來讀取xml文件的工具包有DOM、SAX和JDOM等,但用過的人都知道,它們屬於比較底層的API,寫起來代碼量很大,而且如果修改了xml文件的格式,代碼也要做大幅度的改動。而使用Apache Jakarta的Digester,解析XML文件非常方便且不需要過多的關心底層的具體解析過程。Digester本來僅僅是Jakarta Struts中的一個工具,用於處理struts-config.xml配置文件。顯然,將XML文件轉換成相應的Java對象是一項很通用的功能,這個工具理應具有更廣泛的用途,所以很快它就在Jakarta Commons項目(用於提供可重用的Java組件庫)中有了一席之地。Digester由"事件"驅動,通過調用預定義的規則操作對象棧,將XML文件轉換爲Java對象。
工作原理如下:
Digester底層採用SAX(Simple API for XML)析XML文件,所以很自然的,對象轉換由"事件"驅動,在遍歷每個節點時,檢查是否有匹配模式,如果有,則執行規則定義的操作,比如創建特定的Java對象,或調用特定對象的方法等。此處的XML元素根據匹配模式(matching pattern)識別,而相關操作由規則(rule)定義。
如下xml代碼,右邊是左邊元素對應的匹配模式:
- <datasources> 'datasources'
- <datasource> 'datasources/datasource'
- <name/> 'datasources/datasource/name'
- <driver/> 'datasources/datasource/driver'
- </datasource>
- <datasource> 'datasources/datasource'
- <name/> 'datasources/datasource/name'
- <driver/> 'datasources/datasource/driver'
- </datasource>
- </datasources>
Tomcat與Digester的關係(注意該博客,很多資源)
Tomcat源碼的catalina中利用Digester解析conf/server.xml
Digester處理多層的XML(仔細分析)
==============================================================================
- <?xml version="1.0" encoding="UTF-8?>
- <database>
- <user userName="guest" password="guest">
- </user>
- </database>
1.addObjectCreate(String rule,Class class)
設置節點與Java對象的映射規則,rule指定節點的篩選規則,class設置映射對象。SAX解析時,遇到rule指定的節節點,會創建一個class實例放入堆棧中。
比如:digester.addObectCreate("database/user","com.model.UserBean").解析遇到user節點時,會創建一個UserBean實例並放入堆棧中。
2.addSetProperties(String rule)
設置節點的屬性設置規則。當解析遇到符合rule的節點時,根據屬性列表中的屬性值對,使用Java反射機制使用標準的JavaBean方法設置棧頂對象實例;
比如:digester.addSetProperties("database/user"),解析遇到user節點時,會獲取鍵值對 userName=guest,password=guest,獲得棧頂的UserBean對象,設置實例的userName、password屬性;
解析元素上的屬性
3.addBeanPropertySetter(String rule)
該方法的作用及使用方法類似於addSetProperties,只不過它是用rule所指定的標籤來調用對象的setter。
該方法在tomcat6中貌似沒有。
tomcat6中Digester類路徑爲:import org.apache.tomcat.util.digester.Digester;
不爲:import org.apache.commons.digester.Digester;
4.addSetNext(String rule,String methodName)
設置當前rule節點與父節點的調用規則,當遇到rule節點時,調用堆棧中的次棧頂元素調用methodName方法。將棧頂元素作爲次頂元素指定方法的輸入參數。
比如:digester.addSetNext("database/user","addUser"),調用database實例的addUser,user爲參數
5.addCallMethod(String rule,String methodName,int paraNumber)
該方法同樣設置對象的屬性,但更加靈活,不需要對象具有setter
根據rule規則指定的屬性,調用對象的methodName方法,paraNumber參數是表示方法需要的參數個數,當paraNumber=0時,可以單獨使用,不然需要配合addCallParam方法
比如:digester.addCallMethod("database/user/uerName","setUserName",0);
6.addCallParam(String rule,int paraIndex,String attributeName)
該方法與addCallMethod配合使用,根據rule指定的標籤屬性來調用方法
paraIndex表明需要填充的方法形參序號,從0開始,方法由addCallMethdo指定,attributeName指定標籤屬性名;
使用注意事項:
1.Digester類調用的順序,必須與XML數據文件絕對一致;
2.Digester類依賴於JavaBean規範,類必須符合規範;
3.XML文件中標籤/屬性的名稱必須與Bean中的一致(包括大小寫);
==================================================================
關鍵方法說明
(1) serverDigester.addObjectCreate("Server","com.test.server.digester.Server")
當解析xml文件時,遇到“Server”就初始化一個“com.test.server.digester.Server”對象,並且把該對象壓入棧頂
(2) serverDigester.addSetProperties("Server", "port", "port")
給Server對象註冊port屬性,當解析到Server節點的port屬性時調用Server的setPort方法
(3) serverDigester.addSetNext("Server/Listener", "addListener","com.test.server.digester.Listener")
當解析Server節點下的Listener節點的時候,調用Server對象的addListener方法,把當前Listener對象寫入到Server對象中。無論Server節點下有多少個Listener節點,都會調用addListener方法
(4) serverDigester.addCallMethod("Server/Service/Engine", "setEngine", 0)
Service中添加Engine,調用當前top object的setEngine函數,參數個數爲0
addCallMethod與addBeanPropertySetter方法等價
Example1:
- <?xml version="1.0" encoding="ISO-8859-1"?>
- <student name="llin" age="16" grade="3">
- <subject name="math" teacher="yu" />
- </student>
- package digester;
- import java.util.ArrayList;
- public class Student {
- private String name;
- private int age;
- private int grade;
- private ArrayList<Subject> list = new ArrayList();
- public Student (){
- System.out.println("A student go to school");
- }
- public void add ( Subject subjects ){
- System.out.println("add Subjects " + subjects.getName() + " to the Student: "+ this.getName());
- list.add( subjects );
- }
- /////////////////////////////////////////////////
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- System.out.println( " set age of Student:" + name);
- this.age = age;
- }
- public int getGrade() {
- return grade;
- }
- public void setGrade(int grade) {
- System.out.println( " set score of Student:" + name );
- this.grade = grade;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- System.out.println(" set name pf Student" );
- this.name = name;
- }
- public ArrayList<Subject> getList (){
- return this.list;
- }
- }
- package digester;
- public class Subject {
- private String name;
- private String teacher;
- public Subject() {
- System.out.println("One subjects waiting scheduling!");
- }
- public void print() {
- System.out.println("Subjects :" + name + "of " + teacher + "in schedule");
- }
- /////////////////////////////////////////////////////
- public String getName() {
- return name;
- }
- public void setName(String name) {
- System.out.println(" set name of Subjects:" + name);
- this.name = name;
- }
- public String getTeacher() {
- return teacher;
- }
- public void setTeacher(String teacher) {
- System.out.println(" set teacher of Subjects :" + teacher);
- this.teacher = teacher;
- }
- }
- package digester;
- import java.io.File;
- import java.io.IOException;
- import java.util.Iterator;
- import org.apache.tomcat.util.digester.Digester;
- import org.xml.sax.SAXException;
- public class StudentDigesterTest {
- public static void main ( String [] args ) throws IOException{
- unUseRule();
- //useRule();
- }
- public static void unUseRule(){
- File xml = new File( "../apache-tomcat-6.0.41-src/test/student.xml");
- Digester digester = new Digester();
- digester.addObjectCreate( "student" , "digester.Student" );
- digester.addSetProperties("student");
- digester.addObjectCreate("student/subject" , "digester.Subject");
- digester.addSetProperties("student/subject");
- //上面該句可用這句代替digester.addSetProperties("student/subject","subject","subject");
- /**
- * public void addSetProperties(String pattern,String attributeName,String propertyName)
- */
- digester.addSetNext("student/subject" , "add" );
- Student student = null;
- try {
- student = (Student)digester.parse(xml);
- }catch ( SAXException e ){
- System.out.println("parse with mistakes!");
- } catch (IOException e) {
- e.printStackTrace();
- }
- Iterator it = student.getList().iterator();
- while ( it.hasNext()) {
- }
- }
- public static void useRule(){
- File xml = new File( "../apache-tomcat-6.0.41-src/test/student.xml");
- Digester digester = new Digester();
- digester.addRuleSet(new MyRuleSet());
- Student student = null;
- try {
- student = (Student)digester.parse(xml);
- }catch ( SAXException e ){
- System.out.println("parse with mistakes!");
- } catch (IOException e) {
- e.printStackTrace();
- }
- Iterator it = student.getList().iterator();
- while ( it.hasNext()) {
- }
- }
- }
- package digester;
- import org.apache.tomcat.util.digester.Digester;
- import org.apache.tomcat.util.digester.RuleSetBase;
- public class MyRuleSet extends RuleSetBase{
- @Override
- public void addRuleInstances(Digester digester) {
- digester.addObjectCreate( "student" , "digester.Student" );
- digester.addSetProperties("student");
- digester.addObjectCreate("student/subject" , "digester.Subject");
- digester.addSetProperties("student/subject");
- digester.addSetNext("student/subject" , "add" );
- }
- }
兩種方法結果都爲:
Example2:
viewcache2.xml:
- <?xml version="1.0" encoding="UTF-8" ?>
- <viewcache>
- <areas>
- <area id="1098" parentId="1001" areaType="province" name="上海" ordering="1867" phoneArea="111"/>
- <area id="1099" parentId="1098" areaType="capital" name="北京" ordering="1868" phoneArea="010"/>
- </areas>
- </viewcache>
- package digester;
- import java.util.ArrayList;
- import java.util.List;
- public class ViewCache {
- private ArrayList<Area> areaList = new ArrayList<Area>();
- public ArrayList getAreaList() {
- return areaList;
- }
- public void setAreaList(ArrayList areaList) {
- this.areaList = areaList;
- }
- // 供Digester調用的方法
- public void addArea(Area area) {
- System.out.println("addArea..");
- this.areaList.add(area);
- }
- }
- package digester;
- public class Area {
- private int id;
- private String name;
- private String areaType;
- private int parentId;
- private int ordering;
- // private String zip;
- private String phoneArea;
- public Area(){
- System.out.println("Area constructor..");
- }
- public int getId() {
- return id;
- }
- public void setId(int id) {
- System.out.println( " set id of Area:" + id);
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- System.out.println( " set name of Area:" + name);
- this.name = name;
- }
- public String getAreaType() {
- return areaType;
- }
- public void setAreaType(String areaType) {
- System.out.println( " set areaType of Area:" + areaType);
- this.areaType = areaType;
- }
- public int getParentId() {
- return parentId;
- }
- public void setParentId(int parentId) {
- System.out.println( " set parentId of Area:" + parentId);
- this.parentId = parentId;
- }
- public int getOrdering() {
- return ordering;
- }
- public void setOrdering(int ordering) {
- System.out.println( " set ordering of Area:" + ordering);
- this.ordering = ordering;
- }
- /*public String getZip() {
- return zip;
- }
- public void setZip(String zip) {
- this.zip = zip;
- }*/
- public String getPhoneArea() {
- return phoneArea;
- }
- public void setPhoneArea(String phoneArea) {
- System.out.println( " set phoneArea of Area:" + phoneArea);
- this.phoneArea = phoneArea;
- }
- }
- package digester;
- import java.io.IOException;
- import org.apache.tomcat.util.digester.Digester;
- import org.xml.sax.SAXException;
- public class AreaDigester {
- public ViewCache digester() throws Exception {
- Digester digester = new Digester();
- digester.setValidating(false);
- digester.addObjectCreate("viewcache/areas", ViewCache.class);
- // 指明匹配模式和要創建的類
- digester.addObjectCreate("viewcache/areas/area", Area.class);
- //使用這句可以打印出Area字段set值時的syso語句,下面的打印不出,沒搞清楚。。。
- digester.addSetProperties("viewcache/areas/area");
- // digester.addSetProperties("viewcache/areas/area/id");
- // digester.addSetProperties("viewcache/areas/area/parentId", "parentId", "parentId");
- // digester.addSetProperties("viewcache/areas/area/name", "name", "name");
- // digester.addSetProperties("viewcache/areas/area/areaType", "areaType", "areaType");
- // digester.addSetProperties("viewcache/areas/area/ordering", "ordering", "ordering");
- // //digester.addSetProperties("viewcache/areas/area/zip", "zip", "zip");
- // digester.addSetProperties("viewcache/areas/area/phoneArea", "phoneArea", "phoneArea");
- // 當移動到下一個標籤中時的動作
- digester.addSetNext("viewcache/areas/area", "addArea");
- ViewCache vc = null;
- try {
- vc = (ViewCache) digester.parse("../apache-tomcat-6.0.41-src/test/viewcache2.xml");
- } catch (IOException e) {
- throw new Exception(e);
- } catch (SAXException e) {
- throw new Exception(e);
- }
- return vc;
- }
- public static void main(String[] args) {
- AreaDigester m = new AreaDigester();
- ViewCache vc = null;
- try {
- vc = m.digester();
- } catch (Exception e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- }
- }
結果:
-----------------------------------------------------------------------------------------