上一章:  初始化 bootstrap.init()

https://blog.csdn.net/weixin_42209307/article/details/108580214

我们回到, org.apache.catalina.startup.Bootstrap#main 方法

daemon.load(args) , daemon 就是我们的bootstrap实例, 在这个里面就会解析server.xml 并且创建各个组件的实例,

并且一层一层向下, 初始化组件

我们这节只分享组件实例化, 下一节分享, 组件的初始化

// Bootstrap.java
public static void main(String args[]) {// ....try {String command = "start";if (args.length > 0) {command = args[args.length - 1];}if (command.equals("startd")) {args[args.length - 1] = "start";daemon.load(args);daemon.start();} else if (command.equals("stopd")) {args[args.length - 1] = "stop";daemon.stop();} else if (command.equals("start")) {// 我们是启动命令会进入这个分支daemon.setAwait(true);daemon.load(args);daemon.start();if (null == daemon.getServer()) {System.exit(1);}} else if (command.equals("stop")) {daemon.stopServer(args);// ...}// Bootstrap.javaprivate void load(String[] arguments) throws Exception {// Call the load() methodString methodName = "load";Object param[];Class<?> paramTypes[];if (arguments==null || arguments.length==0) {paramTypes = null;param = null;} else {paramTypes = new Class[1];paramTypes[0] = arguments.getClass();param = new Object[1];param[0] = arguments;}Method method =catalinaDaemon.getClass().getMethod(methodName, paramTypes);if (log.isDebugEnabled()) {log.debug("Calling startup class " + method);}method.invoke(catalinaDaemon, param);}

可以看到是 bootstrap 还是不自己干活, 正如它的翻译, 它只是引导, 它只做了两件事

  1. 获取Catalina 的 load 方法的反射
  2. 执行方法

org.apache.catalina.startup.Catalina#load()

// Catalina.java
public void load() {// 防止重入if (loaded) {return;}loaded = true;// 开始时间long t1 = System.nanoTime();// 啥也没干, 这个方法是废弃的initDirs();// 初始化命名空间, 向内存中添加一下些静态变量, 这个想看的可以自己DEBUG 进去看initNaming();// XML 解析器, 我们重点讲这个Digester digester = createStartDigester();InputSource inputSource = null;InputStream inputStream = null;File file = null;try {try {// 获取server.xml 配置file = configFile();inputStream = new FileInputStream(file);inputSource = new InputSource(file.toURI().toURL().toString());} catch (Exception e) {if (log.isDebugEnabled()) {log.debug(sm.getString("catalina.configFail", file), e);}}//...代码省略// 这里就是去拿默认的server.xml 配置if (inputStream == null) {try {inputStream = getClass().getClassLoader().getResourceAsStream("server-embed.xml");inputSource = new InputSource(getClass().getClassLoader().getResource("server-embed.xml").toString());} catch (Exception e) {if (log.isDebugEnabled()) {log.debug(sm.getString("catalina.configFail","server-embed.xml"), e);}}}//...代码省略try {inputSource.setByteStream(inputStream);// 将Catalina 对象提供给解析器, 创建的实例都会放到Catalina里面去, 并且设置Root节点digester.push(this);// 开始解析, 并且创建对象, 这个我们就不往下跟了, 等有时间, 带各位看看, 因为规则大家都知道了, xml是怎么被解析的, 解析标签以后又该干嘛digester.parse(inputSource);} catch (SAXParseException spe) {log.warn("Catalina.start using " + getConfigFile() + ": " +spe.getMessage());return;} catch (Exception e) {log.warn("Catalina.start using " + getConfigFile() + ": " , e);return;}} finally {if (inputStream != null) {try {inputStream.close();} catch (IOException e) {// Ignore}}}// 这个后面的代码我们下一次再讲, 一步一步慢慢的分析tomcat// 设置server 的 servlet(Catalina) 容器, 就是Bootstrap中的, 同一个对象, 所以到这里就可以知道, servlet 容器是全局存在的, 同一个实例, 因为server 只有一个getServer().setCatalina(this);// -Dcatalina.home=catalina-homegetServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());// -Dcatalina.base=catalina-homegetServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());// 初始化console 打印, initStreams();// 初始化server <Server/>try {// 这里就会一层一层的向下初始化了getServer().init();} catch (LifecycleException e) {if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {throw new java.lang.Error(e);} else {log.error("Catalina.start", e);}}// 结束时间long t2 = System.nanoTime();if(log.isInfoEnabled()) {log.info("Initialization processed in " + ((t2 - t1) / 1000000) + " ms");}}

下面就是我们的本节重点了, 组件是怎么实例化的

Digester digester = createStartDigester();

// Catalina.javaprotected Digester createStartDigester() {long t1=System.currentTimeMillis();// 创建一个解析器对象Digester digester = new Digester();// 是否校验digester.setValidating(false);// 是否校验xml规则digester.setRulesValidation(true);Map<Class<?>, List<String>> fakeAttributes = new HashMap<>();List<String> objectAttrs = new ArrayList<>();objectAttrs.add("className");fakeAttributes.put(Object.class, objectAttrs);// Ignore attribute added by Eclipse for its internal trackingList<String> contextAttrs = new ArrayList<>();contextAttrs.add("source");fakeAttributes.put(StandardContext.class, contextAttrs);digester.setFakeAttributes(fakeAttributes);// 是否使用上下文类加载器, 这个类加载器就是在bootstrap.init(), 设置的上下文 sharedLoaderdigester.setUseContextClassLoader(true);// 我们解读这一块代码, 本文全部都是在为这个做铺垫digester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server");digester.addObjectCreate("Server/GlobalNamingResources","org.apache.catalina.deploy.NamingResourcesImpl");digester.addSetProperties("Server/GlobalNamingResources");digester.addSetNext("Server/GlobalNamingResources","setGlobalNamingResources","org.apache.catalina.deploy.NamingResourcesImpl");digester.addObjectCreate("Server/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Listener");digester.addSetNext("Server/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate("Server/Service","org.apache.catalina.core.StandardService","className");digester.addSetProperties("Server/Service");digester.addSetNext("Server/Service","addService","org.apache.catalina.Service");digester.addObjectCreate("Server/Service/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Service/Listener");digester.addSetNext("Server/Service/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");//Executordigester.addObjectCreate("Server/Service/Executor","org.apache.catalina.core.StandardThreadExecutor","className");digester.addSetProperties("Server/Service/Executor");digester.addSetNext("Server/Service/Executor","addExecutor","org.apache.catalina.Executor");digester.addRule("Server/Service/Connector",new ConnectorCreateRule());digester.addRule("Server/Service/Connector",new SetAllPropertiesRule(new String[]{"executor", "sslImplementationName"}));digester.addSetNext("Server/Service/Connector","addConnector","org.apache.catalina.connector.Connector");digester.addObjectCreate("Server/Service/Connector/SSLHostConfig","org.apache.tomcat.util.net.SSLHostConfig");digester.addSetProperties("Server/Service/Connector/SSLHostConfig");digester.addSetNext("Server/Service/Connector/SSLHostConfig","addSslHostConfig","org.apache.tomcat.util.net.SSLHostConfig");digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",new CertificateCreateRule());digester.addRule("Server/Service/Connector/SSLHostConfig/Certificate",new SetAllPropertiesRule(new String[]{"type"}));digester.addSetNext("Server/Service/Connector/SSLHostConfig/Certificate","addCertificate","org.apache.tomcat.util.net.SSLHostConfigCertificate");digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf","org.apache.tomcat.util.net.openssl.OpenSSLConf");digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf");digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf","setOpenSslConf","org.apache.tomcat.util.net.openssl.OpenSSLConf");digester.addObjectCreate("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd","org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");digester.addSetProperties("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd");digester.addSetNext("Server/Service/Connector/SSLHostConfig/OpenSSLConf/OpenSSLConfCmd","addCmd","org.apache.tomcat.util.net.openssl.OpenSSLConfCmd");digester.addObjectCreate("Server/Service/Connector/Listener",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Service/Connector/Listener");digester.addSetNext("Server/Service/Connector/Listener","addLifecycleListener","org.apache.catalina.LifecycleListener");digester.addObjectCreate("Server/Service/Connector/UpgradeProtocol",null, // MUST be specified in the element"className");digester.addSetProperties("Server/Service/Connector/UpgradeProtocol");digester.addSetNext("Server/Service/Connector/UpgradeProtocol","addUpgradeProtocol","org.apache.coyote.UpgradeProtocol");// Add RuleSets for nested elementsdigester.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/"));addClusterRuleSet(digester, "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));addClusterRuleSet(digester, "Server/Service/Engine/Cluster/");long t2=System.currentTimeMillis();if (log.isDebugEnabled()) {log.debug("Digester for server.xml created " + ( t2-t1 ));}return digester;}

看着好多是吧, 不要紧, 我分析几个典例, 相信你一定就看懂了, 先看第一个, server 标签解析, 这个里面的解析都是SAX解析, 一行一行的来的, 消耗内存小

Server 标签

        digester.addObjectCreate("Server","org.apache.catalina.core.StandardServer","className");digester.addSetProperties("Server");digester.addSetNext("Server","setServer","org.apache.catalina.Server");
  1. digester.addObjectCreate  创建一个解析节点,解析谁呢?

    1. param1:节点名称 Server
    2. param2:解析完以后实例化什么, 这里配置看一个全路径类名
    3. param3:它是什么类型, className, 类名称嘛, 这个很明显就是可以实例化的
  2. digester.addSetProperties 节点名称和Server对应
  3. digester.addSetNext           创建完以后干嘛,干嘛呢
    1. param1:对应节点
    2. param2:调用的函数  setServer
    3. param3:传参类型
  • 流程就是, 解析节点创建实例 -> 创建实例完成以后放置在那里
  • 我们主要看 digester.addSetNext 的第二个参数 , setServer 这个函数在那呢??
  • 因为 Server 没有父节点, 所以它的父节点默认就是Root, Root 就是 Catalina,  这个在哪里可以验证?
// 这就是在解析前, 将Catalina设置进去了
// Digester.java
public void push(Object object) {if (stack.size() == 0) {root = object;}stack.push(object);}
  • 所以可以断定 setServer  是在 Catalina 里面, 事实也是如此
// Catalina.java
public void setServer(Server server) {this.server = server;}

Service 标签

  • service 标签和  server 标签大概一致
  • 只有digester.addObjectCreate 的一个参数可能大部分不是很懂
  • Server/Service , 不仅表面的 xml 的节点关系, 还表面了父子关系
  • 所以这就是为什么 addService 这个在Catalina里面找不到, 因为它在 父组件 StandardServer 里面
    // org.apache.catalina.core.StandardServer#addService@Overridepublic void addService(Service service) {service.setServer(this);synchronized (servicesLock) {Service results[] = new Service[services.length + 1];System.arraycopy(services, 0, results, 0, services.length);results[services.length] = service;services = results;if (getState().isAvailable()) {try {service.start();} catch (LifecycleException e) {// Ignore}}// Report this property change to interested listenerssupport.firePropertyChange("service", null, service);}}

到这里我们本章节的任务已经算是完成了,  各位有兴趣的可以去看 组件的默认构造器, 看在实例化的时候都做了些什么操作,

这里我就不带大家去看了,   再以后的分析中,  自然会讲,

下一步, 将带各位查看组件的初始化, 会涉及部分组件的构造器, 才明白是数据是怎么来的

(5.1) Tomcat 8 源码, 实例化组件相关推荐

  1. (5.2) Tomcat 8 源码, 初始化组件

    上一章, 实例化组件 接着我们上一章, 实例化组件之后开始, 不要迷路了 // Catalina.java public void load() {//... 省略实例化部分代码// 把Catalin ...

  2. Vue源码学习 - 组件化(三) 合并配置

    Vue源码学习 - 组件化(三) 合并配置 合并配置 外部调用场景 组件场景 总结 学习内容和文章内容来自 黄轶老师 黄轶老师的慕课网视频教程地址:<Vue.js2.0 源码揭秘>. 黄轶 ...

  3. Vue源码学习 - 组件化一 createComponent

    Vue源码学习 - 组件化一 createComponent 组件化 createComponent 构造子类构造函数 安装组件钩子函数 实例化 VNode 总结 学习内容和文章内容来自 黄轶老师 黄 ...

  4. 小程序直播带货app源码直播组件接入指引

    小程序直播带货app源码直播组件接入指引 一.简介 小程序直播带货系统,是微信提供给小程序开发者的直播组件.通过调用该组件,商家可以在直播带货app源码中实现直播功能. 按下面的使用说明接入,在你的直 ...

  5. (5.0) Tomcat 8 源码, 初始化 bootstrap

    下载源码 https://www.cnblogs.com/grasp/p/10061577.html 一般启动tomcat 都是使用 startup.bat set "EXECUTABLE= ...

  6. springboot-嵌入式Servlet容器(Tomcat)源码分析以及容器切换

    目录 一.springboot的嵌入式Servlet容器(tomcat) 1.原理 2.源码 (1)ServletWebServerApplicationContext的createWebServer ...

  7. Tomcat学习--源码导入和运行

    2019独角兽企业重金招聘Python工程师标准>>> 一.环境介绍 IDEA 2017.jdk 1.8.tomcat 9.0. maven 3.3.9 tomcat 9.0相对来说 ...

  8. 《WEB服务器——Tomcat》源码学习

    首先奉上tomcat源码下载地址: 点击下载源码 文章目录 第一步:修改源码配置 1.首先用idea打开下载好的源码项目. 2.然后在该项目的根目录中创建一个pom.xml文件,用于引入依赖. 3.紧 ...

  9. tomcat修改源码tomcat不更新

    如果你在eclipse中修改源码发现tomcat不自动更新的时候,可以修改一下Project配置(顶部,Window配置的旁边的旁边),然后 build automatically,把这个勾选上

最新文章

  1. 大数据架构和模式(一)——大数据分类和架构简介
  2. VMware VDI技术与实现
  3. HTML5 API详解(4):最实用的API DeviceOrientation设备传感器
  4. epson r1900 清零软件_EPSON R2000清零软件 R3000 R1800 R1900 R2880 R3880 4880打印机
  5. 字词拼音查询易语言代码
  6. 操作系统--进程和线程
  7. php speex,将微信jssdk录制的speex高清音频转换为wav/mp3
  8. 【短视频运营】短视频制作流程 ( 视频存稿 | 写脚本 | 拍摄收音 | 提词器 | 后期剪辑 | 前测工具 | 检查违禁词 )
  9. ERROR2002(HY000):CantconnecttolocalMySQLserverthroughsocket/tmp/mys
  10. [unity]调用手机摄像头
  11. 特殊时期下捣鼓树莓派4
  12. Unity3d开发MOBA游戏类《王者荣耀》记录(起)
  13. iOS开发 - Xcode使用 - 一直indexing
  14. ssd hdd linux分区方案,windows10+ubuntu 16.04+双硬盘(SSD+HDD)分区(图文)
  15. 设立有限公司需要具备的条件
  16. python爬虫爬取东方财富网股票走势+一些信息
  17. 脑波和眼动连通性分析 python-(1)
  18. mbp 封神台靶场 一(笔记)
  19. Electron系列教程——第一篇:入门
  20. 网上做什么赚钱现在,这4个赚钱小项目分享给你!

热门文章

  1. 最短路径的Dijkstra算法(邻接表)
  2. TensorFlow各版本下载地址,强烈推荐
  3. oracle如何删除可回收归档,Oracle正确删除归档并回收空间的方法
  4. 队列和通知区别_消息队列,阻塞队列
  5. linux中if的作用域,【2017-02-21】分支语句if...else...、分支嵌套、变量的作用域
  6. JAVA之JVM之内存分配与回收策略(二)
  7. java 加法不用_【Java】 剑指offer(65) 不用加减乘除做加法
  8. 切换器黑屏_机房的KVM切换器是什么,故障如何解决?
  9. java电话号码输入_使用可选字母前缀屏蔽输入到电话号码格式
  10. mongodb spring 超时时间_spring data mongodb 配置遇到的几个问题