tomcat源码阅读(二) Digester方法详解
来源:互联网 发布:mac刷新桌面 编辑:程序博客网 时间:2024/05/16 07:48
Digester方法详解:
1. 通读Digester之前先分析下他的结构:
1.1该类继承了方法DefaultHandler2,DefaultHandler2继承了DefaultHandler是和sax解析器配合使用的类。当sax在对字符流进行加工的时候会根据实际情况调用 DefaultHandler中的方法。其使用的设计模式为模板模式。
1.2createStartDigester方法中addObjectCreate、addSetNext的参数最终都是继承自抽象类Rule;方法addRuleSet的参数继承自抽象类RuleSetBase,实现接口RuleSet
1.3总结:理解digester前需要了解的接口和抽象类:DefaultHandler、Rule、RuleSet。
2. DefaultHandler类:
DefaultHandler类中的方法:processingInstruction、ignorableWhitespace、characters、endElement、startElement、endPrefixMapping、startPrefixMapping、endDocument、startDocument、setDocumentLocator、resolveEntity等方法。上面所列出的大多为digester中需要用到的
3. Rule类:主要四个方法 begin 、body、end、finish
4. RuleSet类:addRuleInstances
5. 关系梳理:
(1)catalina类的load方法中两个主要的createStartDigester和digester.parse方法。我们先理解parse方法;createStartDigester方法到后面再说。
(2) digester.parse()是用sax来解析xml的。
2.1根据其使用的模板设计模式,会在 解析xml节点时调用DefaultHandler类中方法。当调用startDocument时会 调用rule.begin。代码如下:该处的rule使用的是接口,实际调用中,是使用的那个实现类,要看rules.get()拿出的对象是什么。这个在后面学习createStartDigester会再提到。
public void startElement(String namespaceURI, String localName, String qName, Attributes list) throws SAXException { boolean debug = log.isDebugEnabled(); if (saxLog.isDebugEnabled()) { saxLog.debug("startElement(" + namespaceURI + "," + localName + "," + qName + ")"); } // Parse system properties list = updateAttributes(list); // Save the body text accumulated for our surrounding element bodyTexts.push(bodyText); if (debug) { log.debug(" Pushing body text '" + bodyText.toString() + "'"); } bodyText = new StringBuffer(); // the actual element name is either in localName or qName, depending // on whether the parser is namespace aware String name = localName; if ((name == null) || (name.length() < 1)) { name = qName; } // Compute the current matching rule StringBuffer sb = new StringBuffer(match); if (match.length() > 0) { sb.append('/'); } sb.append(name); match = sb.toString(); if (debug) { log.debug(" New match='" + match + "'"); } // Fire "begin" events for all relevant rules List rules = getRules().match(namespaceURI, match); matches.push(rules); if ((rules != null) && (rules.size() > 0)) { for (int i = 0; i < rules.size(); i++) { try { Rule rule = (Rule) rules.get(i); if (debug) { log.debug(" Fire begin() for " + rule); } rule.begin(namespaceURI, name, list); } catch (Exception e) { log.error("Begin event threw exception", e); throw createSAXException(e); } catch (Error e) { log.error("Begin event threw error", e); throw e; } } } else { if (debug) { log.debug(" No rules found matching '" + match + "'."); } } }
2.2其余的方法endDocument调用rule.finish、endElement调用rule.body方法等就不在一一列举,代码中很清楚。
public void endDocument() throws SAXException { if (saxLog.isDebugEnabled()) { if (getCount() > 1) { saxLog.debug("endDocument(): " + getCount() + " elements left"); } else { saxLog.debug("endDocument()"); } } while (getCount() > 1) { pop(); } // Fire "finish" events for all defined rules Iterator rules = getRules().rules().iterator(); while (rules.hasNext()) { Rule rule = (Rule) rules.next(); try { rule.finish(); } catch (Exception e) { log.error("Finish event threw exception", e); throw createSAXException(e); } catch (Error e) { log.error("Finish event threw error", e); throw e; } } // Perform final cleanup clear(); }
(3)createStartDigester方法中会创建一些对象的实例,并调用其中的一些方法。用的方式大多为java中的反射机制。
3.1其中addObjectCreate会创建ObjectCreateRule对象,该对象继承自Rule方法,它实现了rule的begin方法,在其中创建了类的实例。
public void begin(Attributes attributes) throws Exception { // Identify the name of the class to instantiate String realClassName = className; if (attributeName != null) { String value = attributes.getValue(attributeName); if (value != null) { realClassName = value; } } if (digester.log.isDebugEnabled()) { digester.log.debug("[ObjectCreateRule]{" + digester.match + "}New " + realClassName); } // Instantiate the new object and push it on the context stack Class clazz = digester.getClassLoader().loadClass(realClassName); Object instance = clazz.newInstance(); digester.push(instance); }
3.2 addSetProperties主要是解析xml节点中的属性值,实现了rule接口的begin方法。
public void begin(Attributes attributes) throws Exception { // Populate the corresponding properties of the top object Object top = digester.peek(); if (digester.log.isDebugEnabled()) { if (top != null) { digester.log.debug("[SetPropertiesRule]{" + digester.match + "} Set " + top.getClass().getName() + " properties"); } else { digester.log.debug("[SetPropertiesRule]{" + digester.match + "} Set NULL properties"); } } // set up variables for custom names mappings int attNamesLength = 0; if (attributeNames != null) { attNamesLength = attributeNames.length; } int propNamesLength = 0; if (propertyNames != null) { propNamesLength = propertyNames.length; } for (int i = 0; i < attributes.getLength(); i++) { String name = attributes.getLocalName(i); if ("".equals(name)) { name = attributes.getQName(i); } String value = attributes.getValue(i); // we'll now check for custom mappings for (int n = 0; n<attNamesLength; n++) { if (name.equals(attributeNames[n])) { if (n < propNamesLength) { // set this to value from list name = propertyNames[n]; } else { // set name to null // we'll check for this later name = null; } break; } } if (digester.log.isDebugEnabled()) { digester.log.debug("[SetPropertiesRule]{" + digester.match + "} Setting property '" + name + "' to '" + value + "'"); } if (!digester.isFakeAttribute(top, name) && !IntrospectionUtils.setProperty(top, name, value) && digester.getRulesValidation()) { digester.log.warn("[SetPropertiesRule]{" + digester.match + "} Setting property '" + name + "' to '" + value + "' did not find a matching property."); } } }3.3 addSetNext方法会创建一个SetNextRule对象,该对象实现了rule的end方法,并在其中调用了指定类中的指定方法。
public void end() throws Exception { // Identify the objects to be used Object child = digester.peek(0); Object parent = digester.peek(1); if (digester.log.isDebugEnabled()) { if (parent == null) { digester.log.debug("[SetNextRule]{" + digester.match + "} Call [NULL PARENT]." + methodName + "(" + child + ")"); } else { digester.log.debug("[SetNextRule]{" + digester.match + "} Call " + parent.getClass().getName() + "." + methodName + "(" + child + ")"); } } // Call the specified method IntrospectionUtils.callMethod1(parent, methodName, child, paramType, digester.getClassLoader()); }3.4 addRule方法就是在规则列表中,简单的添加一条规则。不同的是,实现的方法是rules接口中的add方法。添加的规则有:ConnectorCreateRule、SetAllPropertiesRule、SetParentClassLoaderRule。其中ConnectorCreateRule就是创建一个connector。
public void addRule(String pattern, Rule rule) { rule.setDigester(this); getRules().add(pattern, rule); }RulesBase中的方法:
public void add(String pattern, Rule rule) { // to help users who accidently add '/' to the end of their patterns int patternLength = pattern.length(); if (patternLength>1 && pattern.endsWith("/")) { pattern = pattern.substring(0, patternLength-1); } List list = (List) cache.get(pattern); if (list == null) { list = new ArrayList(); cache.put(pattern, list); } list.add(rule); rules.add(rule); if (this.digester != null) { rule.setDigester(this.digester); } if (this.namespaceURI != null) { rule.setNamespaceURI(this.namespaceURI); } }
3.5addRuleSet方法添加的都是继承自RuleSet的对象,重写了方法addRuleInstances的逻辑。从代码中可以清晰的看到,添加的是tomcat中的engin、host等信息。
// Add RuleSets for nested elements digester.addRuleSet(new NamingRuleSet("Server/GlobalNamingResources/")); digester.addRuleSet(new EngineRuleSet("Server/Service/")); digester.addRuleSet(new HostRuleSet("Server/Service/Engine/")); digester.addRuleSet(new ContextRuleSet("Server/Service/Engine/Host/")); digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Host/Cluster/")); digester.addRuleSet(new NamingRuleSet("Server/Service/Engine/Host/Context/")); // When the 'engine' is found, set the parentClassLoader. digester.addRule("Server/Service/Engine", new SetParentClassLoaderRule(parentClassLoader)); digester.addRuleSet(ClusterRuleSetFactory.getClusterRuleSet("Server/Service/Engine/Cluster/"));
在对象的实现中,addObjectCreate目的是创建对象,setNextSet是调用该对象的指定方法。比如NamingRuleSet对象实现Ejb、Environment、LocalEjb、Resource、Transaction等的初始化动作。EngineRuleSet对象实现Engine和其下的Cluster、Listener、Valve的初始化动作。HostRuleSet对象实现Host和其下的Alias、Cluster、Listener、Valve的初始化。ContextRuleSet对象主要实现Context、Listener、WebappLoader、Manager、Store、Parameter、Resources、Valve等的初始化。
6. 总结:
读懂digester,关键是需要理解DefaultHandler、Rule、RuleSet这三个抽象类和接口的关联关系,了解其使用的设计模式,将其串联起来就容易了。我在读代码时,最难理解的是,不知道为何一句parse就能把server.xml中的配置给加载完了,最后通过学习别人的文章后,逐渐弄懂了。以此记录,继续学习。
- tomcat源码阅读(二) Digester方法详解
- tomcat源码阅读之Digester
- Tomcat源码阅读四:Digester工具
- Tomcat源码阅读二
- tomcat源码阅读步骤二
- tomcat源码中Digester解析
- Tomcat源码阅读(二)Bootstrap
- Tomcat 源码阅读(二)Catalina.load
- Tomcat中Lifecycle详解(源码阅读)
- Tomcat中session详解(源码阅读)
- tomcat解析(六)Digester(二)startElement
- Tomcat源码阅读系列(二)Tomcat总体架构
- Tomcat整体架构(Tomcat源码阅读系列之二)
- digester二
- Digester 详解
- tomcat源码解读一 Digester的解析方式
- tomcat源码阅读-1
- tomcat源码阅读-2
- 谷歌开放人工智能系统
- C++单链表实现冒泡排序
- 使用backtrace获取堆栈信息
- Cocos2d-x 3.7之后控制组件里的onEnter()和onAdd()的用法
- nmon安装部署及结果分析
- tomcat源码阅读(二) Digester方法详解
- java基础知识点二(上)
- 网络应用
- PopupWindow
- 编程之美-判断点是否在三角形内方法整理
- <button>和<input type="button"> 的区别
- iOS视图控制器<1>
- fis3使用起步
- 关于最大加权集求解问题的思路(欢迎大家纠正)