前一章大概看了bootstrap的代码,知道了bootstrap除了主要实例化那三个类加载器,其他都是用CatalinaClassLoaler去加载Catalina类的执行对应方法,主要是init load start stop是这几个方法,在看Catalina源码之前,要首先看下tomcat里面的解析XML配置文件的工具集Digester和Rule。Digester源码在org\apache\tomcat\util\digester\Digester.java,最后编译的jar包是tomcat-util-scan.jar。
Digester****部分
首先看下Digester类的定义public class Digester extends DefaultHandler2
可以看到Digester继承了DefaultHandler2类,我们知道DefaultHandler2是java中使用SAX方式解析XML文件的处理类。这里可以看出tomcat是使用SAX的方式来处理tomcat中的各种XML配置文件的。 看SAX主要是看SAX引擎解析XML的时候的几个回调方法,(startDocument、endDocument、startElement、endElement、characters),至于其他的几个方法可以待到将来更加深入分析的时候去看,现在一个个的来看这几个主要方法
1、 startDocument;
记录日志,实例化log 、saxlog、设置configured为true。
2、 startElement重点方法;
1 //记录log
2 boolean debug = log.isDebugEnabled();
3
4 if (saxLog.isDebugEnabled()) {
5 saxLog.debug("startElement(" + namespaceURI + "," + localName + "," + qName + ")");
6 }
7
8 //格式化xml元素的属性,将${}属性用System属性来替换
9 list = updateAttributes(list);
10
11 //为类似<a>xxxx</a>标签做解析文本的准备
12 bodyTexts.push(bodyText);
13 bodyText = new StringBuilder();
14
15
16 String name = localName;
17 if ((name == null) || (name.length() < 1)) {
18 name = qName;
19 }
20
21 /**
22 类似<a><b></b></a>这个xml标签结构会被解析成
23 a/b
24 */
25 StringBuilder sb = new StringBuilder(match);
26 if (match.length() > 0) {
27 sb.append('/');
28 }
29 sb.append(name);
30 match = sb.toString();
31 if (debug) {
32 log.debug(" New match='" + match + "'");
33 }
34
35 //更具match过滤出Rules,rule是addRuleXXX方法添加的
36 List<Rule> rules = getRules().match(namespaceURI, match);
37 matches.push(rules);
38 if ((rules != null) && (rules.size() > 0)) {
39 //循环调用rule的begin方法
40 for (int i = 0; i < rules.size(); i++) {
41 try {
42 Rule rule = rules.get(i);
43 if (debug) {
44 log.debug(" Fire begin() for " + rule);
45 }
46 rule.begin(namespaceURI, name, list);
47 } catch (Exception e) {
48 log.error("Begin event threw exception", e);
49 throw createSAXException(e);
50 } catch (Error e) {
51 log.error("Begin event threw error", e);
52 throw e;
53 }
54 }
55 } else {
56 if (debug) {
57 log.debug(" No rules found matching '" + match + "'.");
58 }
59 }
3、 characters方法;
1 //记录log
2 if (saxLog.isDebugEnabled()) {
3 saxLog.debug("characters(" + new String(buffer, start, length) + ")");
4 }
5 //类似<a>xxxxx</a>,将xxxxx暂存bodyText
6 bodyText.append(buffer, start, length);
4、 endElement方法;
1 //记log
2 boolean debug = log.isDebugEnabled();
3 if (debug) {
4 if (saxLog.isDebugEnabled()) {
5 saxLog.debug("endElement(" + namespaceURI + "," + localName + "," + qName + ")");
6 }
7 log.debug(" match='" + match + "'");
8 log.debug(" bodyText='" + bodyText + "'");
9 }
10
11 //用system属性格式化bodyText
12 bodyText = updateBodyText(bodyText);
13
14 String name = localName;
15 if ((name == null) || (name.length() < 1)) {
16 name = qName;
17 }
18
19 //获得startElment方法match出的rules
20 List<Rule> rules = matches.pop();
21 if ((rules != null) && (rules.size() > 0)) {
22 String bodyText = this.bodyText.toString();
23 //循环调用rule的body方法,将解析得到的当前标签的body传给rule的body方法,
24 for (int i = 0; i < rules.size(); i++) {
25 try {
26 Rule rule = rules.get(i);
27 if (debug) {
28 log.debug(" Fire body() for " + rule);
29 }
30 rule.body(namespaceURI, name, bodyText);
31 } catch (Exception e) {
32 log.error("Body event threw exception", e);
33 throw createSAXException(e);
34 } catch (Error e) {
35 log.error("Body event threw error", e);
36 throw e;
37 }
38 }
39 } else {
40 if (debug) {
41 log.debug(" No rules found matching '" + match + "'.");
42 }
43 if (rulesValidation) {
44 log.warn(" No rules found matching '" + match + "'.");
45 }
46 }
47
48 //弹出当前的bodyText,给其他标签使用
49 bodyText = bodyTexts.pop();
50 if (rules != null) {
51 //循环调用rule的end方法,注意是反向调用的,最先添加的rule最后被调用end方法
52 for (int i = 0; i < rules.size(); i++) {
53 int j = (rules.size() - i) - 1;
54 try {
55 Rule rule = rules.get(j);
56 if (debug) {
57 log.debug(" Fire end() for " + rule);
58 }
59 rule.end(namespaceURI, name);
60 } catch (Exception e) {
61 log.error("End event threw exception", e);
62 throw createSAXException(e);
63 } catch (Error e) {
64 log.error("End event threw error", e);
65 throw e;
66 }
67 }
68 }
69
70 // Recover the previous match expression
71 int slash = match.lastIndexOf('/');
72 if (slash >= 0) {
73 match = match.substring(0, slash);
74 } else {
75 match = "";
76 }
5、 endDocument方法;
1 //记log
2 if (saxLog.isDebugEnabled()) {
3 if (getCount() > 1) {
4 saxLog.debug("endDocument(): " + getCount() + " elements left");
5 } else {
6 saxLog.debug("endDocument()");
7 }
8 }
9
10 while (getCount() > 1) {
11 pop();
12 }
13
14 //循环调用所用rule的finish方法
15 Iterator<Rule> rules = getRules().rules().iterator();
16 while (rules.hasNext()) {
17 Rule rule = rules.next();
18 try {
19 rule.finish();
20 } catch (Exception e) {
21 log.error("Finish event threw exception", e);
22 throw createSAXException(e);
23 } catch (Error e) {
24 log.error("Finish event threw error", e);
25 throw e;
26 }
27 }
28 //初始化Digester的属性
29 clear();
Rule****部分
我们先看下rule,rule主要是这几个方法,这是所有rule的父类主要几个方法
1 Public abstract class Rule{
2 ………………
3 public Digester getDigester() {
4 return digester;
5 }
6
7 public void setDigester(Digester digester) {}
8 …………..
9 //startElement的时候调用
10 public void begin(String namespace, String name, Attributes attributes) throws Exception {
11 }
12 //endElement的时候调用
13 public void body(String namespace, String name, String text) throws Exception {
14
15 }
16 //endElement的时候调用
17 public void end(String namespace, String name) throws Exception {
18
19 }
20 //endDocument的时候调用
21 public void finish() throws Exception {
22 }
23 }
我们主要分析Digest类中AddRuleXXX中的几个Rule(CallMethodRule、CallParamRule、FactoryCreateRule、ObjectCreateRule、SetNextRule、SetPropertiesRule)
1、 CallMethodRule和CallParamRule配合使用(以xxxxx举例);
当解析到的时候,CallMethodRule的begin方法调用实例化parameter数组push进Digester,调用CallParamRule的begin方法赋值parameter数组
当解析到的时候,从Digester中peek出object,object反射调用method,传入begin的时候解析到的参数
2、 FactoryCreateRule(以xxxxx举例);
Begein方法,解析调用实现了ObjectCreationFactory接口的对象的createObject方法,传入标签的attribute创建对象,push进Digester
End方法,解析到Digester pop出begin push的object
3、 ObjectCreateRule(以<aclassname=’xxxxx’>xxxxx举例)Begin方法,通过catalinaClassLoader加载classname类名的类;
4、 SetNextRuleEnd方法,在parent对象上调用methodName参数的方法,child作为方法参数传入,下图是Digester中ArrayStack的父子Object;

5、 SetPropertiesRule(<aatt1=’1’att2=’2’>);
Begin方法,peek Digester的object,读取标签的attributes设置object的属性,括号中标签为例,设置object的att1属性值1,att2属性值2
Digester中的addRulexxx(String pattern,XXXX),其中pattern参数,和Digester方法startElement中match比较来过滤得到当前标签对应的****rules
-——————————————————————————————————————–
下面是我调用Digester解析一个简单xml的小例子,如果想测试的话需要导入lib下面的2个jar包(tomcat-util-scan.jar、tomcat-util.jar)和bin下面的jar包(tomcat-juli.jar),
我没添加解析Address标签的rule,可以动手试下
实体类
```java
1Address类 2 3 package tomcat9DigesterTest; 4 5 public class Address { 6 7 private String contry; 8 9 private String state; 10 11 public String getContry() { 12 return contry; 13 } 14 15 public void setContry(String contry) { 16 this.contry = contry; 17 } 18 19 public String getState() { 20 return state; 21 } 22 23 public void setState(String state) { 24 this.state = state; 25 } 26 27 28 } 29 30 Container类 31 32 package tomcat9DigesterTest; 33 34 import java.util.ArrayList; 35 import java.util.List; 36 37 public class Container { 38 39 private List<Note> notes = new ArrayList<Note>(); 40 41 public void addNote(Note note){ 42 notes.add(note); 43 } 44 45 public List<Note> getNotes() { 46 return notes; 47 } 48 49 public void writeNote(String issue){ 50 for(Note note: notes){ 51 note.setFrom("huangshi"); 52 note.setTo("shenzhen"); 53 note.setHeading("My Dear"); 54 note.setBody("balabalabalabalabalabalabalabalabalabala"); 55 } 56 } 57 } 58 59 Note类 60 package tomcat9DigesterTest; 61 62 public class Note { 63 64 private String from; 65 66 private String to; 67 68 private String heading; 69 70 private String body; 71 72 public String getFrom() { 73 return from; 74 } 75 76 public void setFrom(String from) { 77 this.from = from; 78 } 79 80 public String getTo() { 81 return to; 82 } 83 84 public void setTo(String to) { 85 this.to = to; 86 } 87 88 public String getHeading() { 89 return heading; 90 } 91 92 public void setHeading(String heading) { 93 this.heading = heading; 94 } 95 96 public String getBody() { 97 return body; 98 } 99 100 public void setBody(String body) { 101 this.body = body; 102 } 103 }
```end
Xml文件
```java
<?xml version="1.0" ?> <note> <to>Tove</to> <from>Jani</from> <heading>Reminder</heading> <body>Don't forget me this weekend!</body> <address contry="USA" state="L.A."></address> <address contry="UK" state="London"></address> </note>
```end
Main类
```java
1package tomcat9DigesterTest; 2 3 import java.io.IOException; 4 import java.io.InputStream; 5 6 import org.apache.tomcat.util.digester.CallMethodRule; 7 import org.apache.tomcat.util.digester.Digester; 8 import org.xml.sax.SAXException; 9 10 public class DigesterTest { 11 12 public static void main(String[] args) throws IOException, SAXException { 13 // TODO Auto-generated method stub 14 Digester digester= new Digester(); 15 16 Container c = new Container(); 17 digester.push(c); 18 19 InputStream is = DigesterTest.class.getClassLoader().getResourceAsStream("test.xml"); 20 21 digester.setValidating(false); 22 23 digester.setNamespaceAware(false); 24 25 digester.addRule("note",new CallMethodRule("writeNote",0)); 26 digester.addObjectCreate("note","tomcat9DigesterTest.Note"); 27 digester.addSetNext("note", "addNote", "tomcat9DigesterTest.Note"); 28 29 digester.parse(is); 30 31 System.out.println(c.getNotes().size()); 32 33 Note note = c.getNotes().get(0); 34 System.out.println(note.getFrom()+":"+note.getTo()+":"+note.getHeading()+":"+note.getBody()); 35 } 36 }
```end
最近发现,tomcat用的xml解析方式,现在是apache commons下的一个项目
http://commons.apache.org/proper/commons-digester/guide/core.html
版权声明:本文不是「本站」原创文章,版权归原作者所有 | 原文地址:
下一篇:03、Tomcat源码:Bootstrap类代码分析
阅读全文
江小北的笔记 AIJIANGSIR.COM -沪ICP备2023041623号-1