文章目录

  • 启动流程分析
  • Pre
  • load 加载初始化
    • 总体预览
    • 源码解析
      • load()
        • Server初始化
          • Service初始化
            • Engine初始化
            • Connector 初始化
  • 小结


启动流程分析


Pre

Tomcat - Tomcat 8.5.55 启动过程源码分析阶段一_init实例化Bootstrap

我们分析了 init 的主要功能,实例化Bootstrap , 调用init 通过反射调用Catalina#setParentClassLoader ,后面调用的load 和 start方法 均为 反射调用的Catalina对象的load和start 方法。


load 加载初始化

总体预览

源码解析

load()

我们梳理关键脉络

// Digester对象  用于解析 server.xmlDigester digester = createStartDigester();// tomcat的配置文件  server.xmlfile = configFile();// 解析 xml  重点关注返回的对象  rootdigester.parse(inputSource);

进到这个parse方法

 /*** Parse the content of the specified input source using this Digester.* Returns the root element from the object stack (if any).** @param input Input source containing the XML data to be parsed* @return the root object* @exception IOException if an input/output error occurs* @exception SAXException if a parsing exception occurs*/public Object parse(InputSource input) throws IOException, SAXException {configure();getXMLReader().parse(input);return root;}

那我们看下我们source目录下的精简后的server.xml

结合tomcat总体的架构图,套娃结构 , server-service-----connector/container-----engine-----host-----context-----wrapper

刚才debug出来的root对象是不是很好理解了呢?

我们看下LifeCycle接口的继承关系, tomcat类的命名其实是很规范的 StandardXXXX

那继续看下 root对象的 及 配置文件的关系

Server初始化

继续往下跟


//  Servier初始化getServer().init();

调用的是 LifeCycle的init接口 , 跟进去可以看到是进入到了 LifeCycleBase这个抽象类的init方法

在init方法中 ,调用

 // 初始化的关键方法 (抽象方法 交由子类实现  设计模式中的模板模式)initInternal();

可以看到这个方法是抽象方法 , 具体的实现由继承了LifeCycleBase这个抽象的子类实现具体的业务逻辑。

这里使用了模板模式 . 我们看下LifeCycleBase抽行类的具体实现

很规范的实现 ,每个组件实例化 都要从LifeCycleBase中走一遍 ,自行实现 init方法。

既然这里是Server, 那到StandardServer # initInternal 中看下

最重要的代码 实例化Service

 for (Service service : services) {service.init();}

这里可以看出来,Service 支持配置多个,不过通常情况下,不建议这么做。 想配置多个,干嘛不多起个tomcat呢?


Service初始化

同样的模板模式 , 还是会调用到 StandardService # initInternal ,精简后的核心代码如下

 @Overrideprotected void initInternal() throws LifecycleException {super.initInternal();if (engine != null) {engine.init();} // Initialize our defined Connectorssynchronized (connectorsLock) {for (Connector connector : connectors) { connector.init();    }}}

可以看到 StandardService # initInternal 中 主要干了两件事儿 engine.init 和 connector.init


Engine初始化

同样的老一套,模板模式, 跟进到 StandardEngine # initInternal

    @Overrideprotected void initInternal() throws LifecycleException { getRealm();super.initInternal();}

可以看到调用的是父类的 initInternal , 父类 ContainerBase

   @Overrideprotected void initInternal() throws LifecycleException {BlockingQueue<Runnable> startStopQueue = new LinkedBlockingQueue<>();startStopExecutor = new ThreadPoolExecutor(getStartStopThreadsInternal(),getStartStopThreadsInternal(), 10, TimeUnit.SECONDS,startStopQueue,new StartStopThreadFactory(getName() + "-startStop-"));startStopExecutor.allowCoreThreadTimeOut(true);super.initInternal();}

干了件啥事儿? 无非就是实例化了一个连接池startStopExecutor , 这个线程池的主要作用是在后面的start方法中使用。Engine可以配置多个Host,这个连接池的作用主要是为了并行初始化Host


Connector 初始化

继续 StandardService # initInternal , 接着 Connector 实例化, for循环嘛 ,一看就是支持配置多个Connector

   for (Connector connector : connectors) { connector.init();    }

Connector# initInternal

核心代码

 @Overrideprotected void initInternal() throws LifecycleException {super.initInternal();// Initialize adapter 并绑定 protocolHandleradapter = new CoyoteAdapter(this);protocolHandler.setAdapter(adapter);// protocolHandler初始化,主要是 内部EndPoint的初始化 protocolHandler.init();}

CoyoteAdapter 对应tomcat架构图,是不是就是 Http 和 Servlet 之间用来做转换的那个Adapter ?

protocolHandler.setAdapter(adapter) 绑定

继续看

  // protocolHandler初始化,主要是 内部EndPoint的初始化 protocolHandler.init();

进入 AbstractHttp11Protocol # init

  @Overridepublic void init() throws Exception { for (UpgradeProtocol upgradeProtocol : upgradeProtocols) {configureUpgradeProtocol(upgradeProtocol);}super.init();}

关注 super.init(); 调用抽象父类AbstractProtocol ,精简后的代码如下

 @Overridepublic void init() throws Exception {String endpointName = getName();endpoint.setName(endpointName.substring(1, endpointName.length()-1));endpoint.setDomain(domain);// 通信端点的初始化endpoint.init();}

核心: endpoint.init();

调用 AbstractEndpoint # init

public void init() throws Exception {if (bindOnInit) {bind();bindState = BindState.BOUND_ON_INIT;}}

重点是bind 方法

NioEndpoint ,我们这里的版本是tomcat8+, 默认的是NIO

精简后的核心代码如下:

 @Overridepublic void bind() throws Exception {if (!getUseInheritedChannel()) {// 获取NIO 通道serverSock = ServerSocketChannel.open();socketProperties.setProperties(serverSock.socket());InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));// 绑定端口,但尚未使用accept获取客户端连接serverSock.socket().bind(addr,getAcceptCount());} }

至此,load方法完毕


小结

通过一层层的分析,tomcat套娃式的设计,使用模板模式,一层层的初始化 ,是不是有了更深刻的理解了呢?

load完了,接下来我们来看下start阶段都干了啥事儿,继续下一篇 ~

Tomcat - Tomcat 8.5.55 启动过程源码分析阶段二_load加载初始化相关推荐

  1. Tomcat - Tomcat 8.5.55 启动过程源码分析阶段三_start阶段

    文章目录 启动流程分析 Pre Star阶段 start总览 start源码分析 StandardServer Start StandardService Start StandardEngine S ...

  2. Tomcat - Tomcat 8.5.55 启动过程源码分析阶段一_init实例化Bootstrap

    文章目录 Pre 生命周期统一管理组件LifeCycle 启动入口类查找 启动流程分析 启动总览 init 实例化 Bootstrap Pre 上篇我们搭建了tomcat的源码环境: Tomcat - ...

  3. spring项目一启动就自动运行方法(资源加载初始化)

    参考一个写的不错的博客,原文请看: https://www.cnblogs.com/baixianlong/p/11117665.html 记录几种常用的方式 1.实现ApplicationRunne ...

  4. SpringBoot2 | SpringBoot启动流程源码分析(一)

    首页 博客 专栏·视频 下载 论坛 问答 代码 直播 能力认证 高校 会员中心 收藏 动态 消息 创作中心 SpringBoot2 | SpringBoot启动流程源码分析(一) 置顶 张书康 201 ...

  5. Android系统默认Home应用程序(Launcher)的启动过程源码分析

    在前面一篇文章中,我们分析了Android系统在启动时安装应用程序的过程,这些应用程序安装好之后,还须要有一个Home应用程序来负责把它们在桌面上展示出来,在Android系统中,这个默认的Home应 ...

  6. Activity启动流程源码分析-浅析生命周期函数

    源码分析 接着上一篇 Activity启动流程源码分析-setContentView源码阅读 的讲解,本节介绍一下Activity的生命周期函数何时被调用 要看Activity的生命周期函数何时被调用 ...

  7. Doris FE启动流程源码详细解析

    Doris FE启动流程源码详细解析 一.简介 Apache Doris是一个现代化的MPP分析型数据库产品.仅需亚秒级响应时间即可获得查询结果,有效地支持实时数据分析.Apache Doris的分布 ...

  8. Android音频框架之二 用户录音启动流程源码走读

    前言 此篇是对<Android音频框架之一 详解audioPolicy流程及HAL驱动加载>的延续,此系列博文是记录在Android7.1系统即以后版本实现 内录音功能. 当用户使用 Au ...

  9. Service通过onBind跨进程启动流程源码探究

    根据<Activity跨进程启动流程源码探究>我们可以清楚以下几点: 1)Context的通用实现是在ContextIml这个类中 2)Activity的启动过程需要借助ActivityM ...

最新文章

  1. HDU 6143 Killer Names (组合数学+DP)
  2. expected:instruction or directive
  3. 想在创建虚拟机的时候指定ip调研
  4. STM32学习笔记(五)——通用定时器计数延时
  5. Linux: wget 使用技巧
  6. 03-postgresql报错ERROR: operator does not exist: numeric = character varyin
  7. 设计模式网站 http://www.cnblogs.com/justinw/archive/2007/02/06/641414.html
  8. Atitit 法学处罚方式模式 目录 1. 申诫罚、财产罚和能力罚 1 1.1. 申诫罚 (警告和通报批评 ) 1 1.2. 财产罚是指使被处罚人的财产权利和利益受到损害的行政处罚。 2 1.2
  9. 暴力解决配置HTTPS后无法使用Hermit
  10. 计算机感染冲击波,CIH、爱虫、冲击波、熊猫烧香,对这4种网络病毒你了解多少?...
  11. npp夜光数据介绍 viirs_对 VIIRS/NPP 夜光数据的解读
  12. 部署和应用程序没有匹配的安全区域错误
  13. 放射技师计算机辅助诊断,基于CT影像的肺癌计算机辅助诊断关键技术研究
  14. 路由器工作原理及路由、路由表
  15. numpy数组array的shape属性-1维、2维···
  16. Utf8和Unicode转换问题 C语言 千字文问题
  17. 计算机网络--第一章 概述--课后习题答案
  18. mysql批量删除5000条数据_mysql批量删除大量数据
  19. 网站建设的整体项目三步骤
  20. ETL工具Informatica开发流程 综合应用 电信通话计费系统开发项目案例10

热门文章

  1. unity保存运行时的操作_Unity运行时保存prefab的方法一则
  2. gcc a.c 究竟经历了什么
  3. jet nano 车道识别
  4. dailykt爬取tushare 数据存入本地mysql
  5. 关于计算机应用技术的周记,计算机应用技术专业实习周记范文
  6. 深度学习数学基础(三): 激活函数、正则化函数、损失函数、评价指标
  7. tableau可视化数据分析60讲(三)-tableau文件、数据类型及常用数据术语
  8. 【机器学习算法-python实现】决策树-Decision tree(1) 信息熵划分数据集
  9. MapReduce编程实战之“I/O”
  10. 账号 linux_Linux入门之UID和GID(用户ID和组ID)