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都是使用不同的参数调用了该脚本该脚本的使用方法如下(引自该脚 ...
随机推荐
- node 问题
安装:使用.msi直接安装就好,环境变量已经设置好了 1.问题:验证node是否正确安装 办法:直接计算1+1:创建服务器. 在项目文件夹的路径下,输入node命令,会看到一个提示符,这里只能输入直接 ...
- bootstrap 问题
less; sass: css预处理:可以直接使用.css,也可以修改.less,生成定制化的css CDN: 服务,使用这个效果会更好.theme一般不引入,jquery一般在js之前引入. 使用b ...
- hibernate 一对多,由谁维护性能最优
举例如下 Customer类: public class Customer { private int id; private String name; private Set orders = ne ...
- What if you are involved in an automobile accident in the US
What if you are involved in an automobile accident in the US With increasing Chinese tourists and vi ...
- Bitcoin
看李笑来老师的2013演讲——Bitcoin is not virtual currency,it is a real world. 1.由于bitcoin的算法中进行有上限量的发布,所以这是不会出现 ...
- inline函数的作用
(一)inline函数(摘自C++ Primer的第三版) 在函数声明或定义中函数返回类型前加上关键字inline即把min()指定为内联. inline int min(int first, int ...
- 【python】基础入门
1.正则表达式 import re sql="aaa$1bbbbccccc$2sdfsd gps_install_note_id =$3;" regexp=r'\$\d+' # 编 ...
- Java计算手机九宫格锁屏图案连接9个点的方案总数
(一)问题 九宫格图案解锁连接9个点共有多少种方案? (二)初步思考 可以把问题抽象为求满足一定条件的1-9的排列数(类似于“八皇后问题”),例如123456789和987654321都是合法的(按照 ...
- SQL 取两日期的记录
SELECT TOP 1000 [ID] ,[SourcePageID] ,[PlatformType] ,[CreateTime] FROM [home_sendor ...
- MongoDB Windowns 配置使用
MongoDB 下载 MongoDB 提供了可用于 32 位和 64 位系统的预编译二进制包,你可以从MongoDB官网下载安装,MongoDB 预编译二进制包下载地址:https://www.mo ...