tomcat启动(三)Catalina分析-load方法分析
load()方法按从上到下顺序分析(主要分析本人所没学过的知识点,其它略过。。。)。
Digester类作用
使用sax技术对xml进行解析
未开始解析时Digester.push(this)这个用来为catalina设置server
Digester的stack对象栈中持有Catalina对象,
解析xml过程中需要用到的类:
Rule:这个类有很多子类,为解析时遇到不同的匹配模式pattern调用不同的处理动作即不同rule。
当解析到开始标记时会调用其子类ObjectCreateRule.begin()方法.
如解析到<Server>时就会创建StandardServer类的实例并反射调用Digester的stack栈顶对象的setter方法(调用的方法通过传入的name值确定)。
IntrospectionUtils.setProperty(top, name, value)top栈顶对象,name要设置的属性名---方法名的一部分,value要设置的属性值
刚开始时栈顶元素是Catalina,即调用Catalina.setServer(Server object)方法设置Server为后面调用Server.start()做准备
然后将StandardServer对象实例放入Digester的stack对象栈中,
如上面所示会调用setter方法设置NamingResourcesImpl、NamingContextListener。调用addService()方法设置service
当解析到<service>时StandardService实例化,并设置StandardService的Connector、Executor:StandardThreadExecutor、Container
上面Server,Service,Executor,Container,Connector对象设置都是在解析过程中设置了。
- A Digester processes an XML input stream by matching a series of element nesting
- patterns to execute Rules that have been added prior to the start of parsing. This
- package was inspired by the XmlMapper class that was part of Tomcat 3.0 and 3.1,
- but is organized somewhat differently.
Digester通过匹配一系列元素嵌套模式来处理XML输入流,以执行在开始解析之前添加的规则。
该软件包受到作为Tomcat 3.0和3.1的一部分的XmlMapper类的启发,但是它的组织方式略有不同。
具体的对象设置过程请跳转查看:
Catalina.createDigester方法详细理解
- /**如果还有一个指定的字符流,SAX解析器将忽略这一点,但它会使用一个字节流来优先打开一个URI连接本身。
- 如果应用程序知道字节流的字符编码,则应使用setEncoding方法进行设置。*/
- inputSource.setByteStream(inputStream);
三、digester解析xml文件
digester.push(this);将catalina类放入对象栈顶
digester.parse(inputSource);这里开始解析xml数据资源
上面load方法中知道inputSource是指catalina.base/conf/server.xml文件字节流
public Object parse(InputSource input) {
configure();//提供这个Digester实例的懒惰配置的钩子。默认实现什么都不做,但子类可以根据需要重写。
getXMLReader().parse(input);
return (root);
}
返回用于解析输入文档的XMLReader。 FIX ME:在JAXP / XERCES中有一个bug,阻止使用包含DTD的模式的解析器。
- public XMLReader getXMLReader() throws SAXException {
- if (reader == null) {
- reader = getParser().getXMLReader();
- }
- reader.setDTDHandler(this);
- reader.setContentHandler(this);
- if (entityResolver == null) {
- reader.setEntityResolver(this);
- } else {
- reader.setEntityResolver(entityResolver);
- }
- reader.setProperty("http://xml.org/sax/properties/lexical-handler", this);
- reader.setErrorHandler(this);
- return reader;
- }
getParser()
创建一个SAXParser
通过getFactory()获得SAXParserFactory工厂类
工厂类调用newSAXParser()创建parser实例
- public SAXParser getParser() {
- // Return the parser we already created (if any)
- if (parser != null) {
- return (parser);
- }
- // Create a new parser
- try {
- parser = getFactory().newSAXParser();
- } catch (Exception e) {
- log.error("Digester.getParser: ", e);
- return (null);
- }
- return (parser);
- }
得到XMLReader
SAXParser.getXMLReader() 返回由该类实现封装的org.xml.sax.XMLReader
getXMLReader方法中reader.setDTDHandler(this)注册DTD事件处理程序,将会监听SAXParser解析器报告的DTD事件
reader.setErrorHandler(this);注册错误事件处理程序
reader.setContentHandler(this);
- 注册内容事件处理程序。如果应用程序没有注册内容处理程序,SAX解析器报告的所有内容事件将被默认忽略。
- 应用程序可以在解析的中间注册一个新的或不同的处理程序,而SAX解析器必须立即开始使用新的处理程序
- 在SAX编程中,需要为XMLReader设置相应的ContentHandler,
该Handler的startDocument,endDocument,startElement,endElement及characters等方法将用于响应解析xml时的标签事件,
可看到Digester继承于DefaultHandler类,而该类则实现ContentHandler接口,
因此在对server.xml解析时将相应地调用到Digester的startDocument,endDocument,startElement,endElement及characters等方法
最后返回一个xmlreader执行
- startDocument,endDocument,startElement,endElement及characters等方法将会被调用
- 提供定位器:如果这样做,它必须通过调用此方法在调用ContentHandler接口中的任何其他方
- 法之前将定位器提供给应用程序。定位器允许应用程序确定任何文档相关事件的结束位置,即使
- 解析器没有报告错误。通常,应用程序将使用此信息来报告其自身的错误(例如与应用程序业务
- 规则不匹配的字符内容)
处理通知文档的开头,这里主要设置的编码The encoding used by the source XMl document.
((DocumentProperties.Encoding) root).setEncoding(((Locator2) locator).getEncoding());
再开始startElement()方法之前会先调用
startPrefixMapping(String prefix, String namespaceURI)//命名空间前缀进入范围的通知处理方法
这个方法主要是用HashMap<String, ArrayStack<String>>
namespaces 变量以prefix为key,ArrayStack为值保存数据ArrayStack保存着namespaceURI
- ArrayStack<String> stack = namespaces.get(prefix);
- if (stack == null) {
- stack = new ArrayStack<>();
- namespaces.put(prefix, stack);
- }
- stack.push(namespaceURI);
SAX XML reader将自动替换元素和属性名称的前缀。
然而,有些情况下,当应用程序需要在字符数据或属性值中使用前缀时,它们无法安全地自动扩展; start / endPrefixMapping事件将信息提供给应用程序,以在必要时在这些上下文中扩展前缀。
startPrefixMapping事件都将在相应的startElement事件之前立即发生,并且所有endPrefixMapping事件都将在相应的endElement事件之后立即发生
2、Digester.startElement(String namespaceURI, String localName, String qName, Attributes list)
- namespaceURI The Namespace URI, or the empty string if the element has no
- Namespace URI or if Namespace processing is not being performed.
命名空间URI,如果元素没有命名空间URI或未执行命名空间处理,则为空字符串
- localName
- The local name (without prefix), or the empty string if Namespace processing is
- not being performed.
本地名称(无前缀),或为空字符串(如果命名空间处理) 没有执行。
qName The qualified name (with prefix), or the empty string- if qualified names are not available.
限定名称(带前缀)或为空字符串 如果限定名称不可用。
list The attributes attached to the element. If- there are no attributes, it shall be an empty Attributes object.
附加到元素的属性。如果没有属性,它将是一个空的Attributes对象。
到达XML元素的开始处理通知
updateAttributes(list)更新属性中的系统值引用
格式为“$ {xxx}”的文本都将被系统属性中适当的值替换。
初始化标签体内容
bodyTexts用于周围元素的正文文本字符串缓冲区堆栈。The stack of body text string buffers for surrounding elements.
bodyText当前元素标签内的正文内容
获取路径名
将标签的路径字符赋给name。XML格式如:<Servers><Server><Server></Servers>,
当解析到<Server>标签时路径则为Servers/Server,在得到路径后又将该路径赋予match变量;
得到与标签体路径名匹配的Rule List,触发其begin方法
这部分内容是tomcat解析xml的重要部分
当遇到匹配的XML元素的开始时调用此方法。默认实现委托到不推荐使用的方法,而不使用命名空间和名称参数,以保留向后兼容性。
然后这个方法内调用Rule.begin(Attributes attributes) 开始匹配xml元素
3、Digester.characters(char[] buffer, int start, int length) 处理从XML元素的正文接收到的字符数据的通知。
buffer The characters from the XML document来自XML文档的字符
start Starting offset into the buffer开始偏移到缓冲区
length Number of characters from the buffer缓冲区中的字符数
- bodyText.append(buffer, start, length);接受元素标签内的正文内容
4、Digester.endElement(String namespaceURI, String localName, String qName)处理到达的XML元素的结束标记的通知
将bodyText中的变量值替换,如标签体中有${catalina.base},会使用System.getProperties()提取系统catalina.base的属性值
获取与标签路径名匹配的Rule,触发其body及end方法
matches再startElement中被复值了
List<Rule> rules = getRules().match(namespaceURI, match);
matches.push(rules);
- // Parse system properties
- bodyText = updateBodyText(bodyText);
- List<Rule> rules = matches.pop();
- rule.body(namespaceURI, name, bodyText);
- // Recover the body text from the surrounding element
- bodyText = bodyTexts.pop();
- rule.end(namespaceURI, name);
- // Recover the previous match expression
- int slash = match.lastIndexOf('/');
- if (slash >= 0) {
- match = match.substring(0, slash);
- } else {
- match = "";
- }
执行完endElement()方法后元素标签解析完毕需要取消注册此前缀映射
在Digester.endPrefixMapping(String prefix)就是处理的地方
- ArrayStack<String> stack = namespaces.get(prefix);
- stack.pop();
- if (stack.empty())
- namespaces.remove(prefix);
5、Digester.endDocument()
方法内容为:弹出所有还在栈中的对象,执行所有Rule的finish方法,执行clear方法清空相关堆栈(clear方法将Digester定义的变量设置为null,configure设置为false)
到这里xml解析完成。等有空再把上面缕缕
tomcat启动(三)Catalina分析-load方法分析的更多相关文章
- tomcat启动(三)Catalina简要分析
上篇解析Bootstrap到 daemon.setAwait(true); daemon.load(args); daemon.start(); 这三个方法实际是反射调用org.apache.cata ...
- scala中ClassOf、asInstenceOf、isInstanceOf三个预定义方法分析
classOf.isInstanceOf.asInstanceOf三个预定义方法分析 Scala的三个预定义(predefined)方法,我们经常用到:它们用来感觉很简单, 但是里面还是隐藏了一些细节 ...
- tomcat启动控制台中文乱码问题解决方法
tomcat启动控制台中文乱码问题解决方法,修改tomcat安装路径/conf/logging.properties文件 java.util.logging.ConsoleHandler.encodi ...
- tomcat启动(四)Catalina分析-server的init()方法
上一回load()方法解析讲到xml解析完成. load()内部接下来会获取server getServer().setCatalina(this); 这个server从createStartDige ...
- [Tomcat 源码分析系列] (二) : Tomcat 启动脚本-catalina.bat
概述 Tomcat 的三个最重要的启动脚本: startup.bat catalina.bat setclasspath.bat 上一篇咱们分析了 startup.bat 脚本 这一篇咱们来分析 ca ...
- tomcat启动(五)Catalina分析-service.init
上篇写到StandardService.init() 这个方法做什么呢?一起来看看. 这个类也是实现了Lifecycle 如图.这个图中i表示Interface接口.如Lifecycle,Contai ...
- 阿里云 centos7 tomcat 启动巨慢的解决方法(几分钟)
方法一: 通过修改Tomcat启动文件-Djava.security.egd=file:/dev/urandom 通过修改JRE中的java.security文件securerandom.source ...
- tomcat启动(六)Catalina分析-StandardServer.start()
从链接 Tomcat中组件的生命周期管理公共接口Lifecycle 可以知道调用的是StandardServer.startInternal() @Override protected void st ...
- Tomcat启动脚本catalina.sh
1 - 概述脚本catalina.sh用于启动和关闭tomcat服务器,是最关键的脚本另外的脚本startup.sh和shutdown.sh都是使用不同的参数调用了该脚本该脚本的使用方法如下(引自该脚 ...
随机推荐
- C++ 11可变参数接口设计在模板编程中应用的一点点总结
概述 本人对模板编程的应用并非很深,若要用一句话总结我个人对模板编程的理解,我想说的是:模板编程是对类定义的弱化. 如何理解“类定义的弱化”? 一个完整的类有如下几部分组成: 类的名称: 类的成员变量 ...
- NoSQL: Cassandra, HBase, RocksDB
转自: http://www.linkedin.com/pulse/nosql-cassandra-hbase-rocksdb-siddharth-anand I've had the pleasur ...
- hdu 5037 周期优化
http://acm.hdu.edu.cn/showproblem.php?pid=5037 有只青蛙踩石子过河,河宽m,有n个石子坐标已知.青蛙每次最多跳L.现在可以在河中再放一些石子,使得青蛙过河 ...
- 网友写的解决uniGUI限制的方法
群友写的解决uniGUI试用版限制修改SessionTimeOut,思路很精巧,贴过来分享,感谢朋友的奉献.当然,如果真正用uniGUI实做项目,买份正版是正道! var UniServerOpt ...
- WPF Auto LogOff
Implementation of Auto Logoff Based on User Inactivity in WPF Application http://www.codeproject.com ...
- linux系统编程之信号(二):信号处理流程(产生、注册、注销、执行)
对于一个完整的信号生命周期(从信号发送到相应的处理函数执行完毕)来说,可以分为三个阶段: 信号诞生 信号在进程中注册 信号在进程中的注销 信号处理函数执行 1 信号诞生 信号事件 ...
- 关于微信小程序登录,后端如何生成3rd_session?(后端为c#)
各位大神,请教一个问题,现在是小程序端调用wx.login后,将code传入后端接口,后端发起微信服务器request获取openid和session_key,后端再自定义生成一个登录状态:3rd_s ...
- [ASP.NET]ASP.NET中常用的26个优化性能方法
1. 数据库访问性能优化 数据库的连接和关闭 访问数据库资源需要创建连接.打开连接和关闭连接几个操作.这些过程需要多次与数据库交换信息以通过身份验证,比较耗费服务器资源.ASP.NET中提供了连接池( ...
- 在centos7升级jenkins
找到jenkins的位置 使用下面的命令 ps -aux | grep jenkins enkins 5954 7.9 22.5 2695800 421088 ? Ssl 20:5 ...
- CodeForces 540C Ice Cave (BFS)
http://codeforces.com/problemset/problem/540/C Ice Cave Time Limit:2000MS Memory Limit:262 ...