Tomcat -- 启动流程

article/2025/8/28 4:50:43

启动流程

      • web概念
      • tomcat启动原理
        • 启动流程
        • 启动源码
        • 源码跟踪
          • startup.bat 启动文件
          • catalina.bat (bootstrap.jar)
          • 启动入口 Bootstrap.main
        • Bootstrap初始化组件
          • 初始化Bootstrap -- bootstrap.init
          • 加载Bootstrap -- daemon.load(args)
          • 加载Catalina -- Catalina.load
          • 初始化Server -- Lifecycle.init()
          • 初始化Service -- service.init
          • 初始化Connector -- Connector.initInternal
          • 初始化ProtocolHandler
          • 初始化EndPoint -- AbstractEndpoint.init
          • 绑定Servlet
        • Bootstrap启动
          • 启动Bootstrap -- bootstrap.start
          • 启动Catalina.start
          • 启动Server -- Lifecycle.start
          • 启动Service -- StandardService.startInternal
          • 启动Connector -- Connector.startInternal
          • 启动ProtocolHandler -- AbstractProtocol.start
          • 启动Endpoint
          • Acceptor接收器 -- socket.accept

web概念

  1. 软件架构
    a. C/S:客户端、服务器端架构,如微信,QQ
    b. B/S:浏览器、服务器端架构,如淘宝等门户网站
  2. 资源类别
    a. 静态资源:所有用户访问得到的结果都一样,称为静态资源,可以直接被浏览器解析,如html、css、jpg等
    b. 动态资源:每个用户访问得到的结果可能不一致,动态资源被访问后需要先转换为静态资源,再返回给浏览器,由浏览器解析,如:jsp、servlet等
  3. 网络三要素
    a. ip:电子设备在网络的唯一标识
    b. 端口:应用程序在计算机中的唯一标识
    c. 传输协议:规定数据传输的规则

tomcat启动原理

  • 加载tomcat配置文件,初始化容器组件,监听对应的端口号,准备接受客户端请求
    在这里插入图片描述

启动流程

  • 启动tomcat,执行bin/startup.bat脚本,调用catalina.bat脚本
  • 执行调用BootStrap中main方法,调用init方法,通过反射创建Catalina对象及初始化类加载器
  • main方法中调用load方法,会调用Catalina的load方法
  • Catalina的load方法会进行Server中的一系列主键的初始化工作,并构造Digester对象,负责解析XML
  • 加载tomcat配置文件,初始化容器组件,监听对应的端口号,准备接受客户端请求

启动源码

生命周期方法(Lifecycle)

  • 所有组件都存在初始化、启动、停止等生命周期方法,tomcat基于生命周期管理抽象成Lifecycle接口
  • 组件Server、Service、Container、Executor、Connector都实现Lifecycle,通过Lifecycle统一管理个组件的生命周期接口
    ○ init:初始化组件接口
    ○ start:启动组件接口
    ○ stop:停止组件接口
    ○ destroy:销毁组件接口

组件默认实现
在这里插入图片描述

源码跟踪

在这里插入图片描述

startup.bat 启动文件
:okHome
//调用catalina.bat 
set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat"rem Check that target executable exists
if exist "%EXECUTABLE%" goto okExec
echo Cannot find "%EXECUTABLE%"
echo This file is needed to run this program
goto end
:okExecrem Get remaining unshifted command line arguments and save them in the
set CMD_LINE_ARGS=
:setArgs
if ""%1""=="""" goto doneSetArgs
set CMD_LINE_ARGS=%CMD_LINE_ARGS% %1
shift
goto setArgs
:doneSetArgs
//执行
call "%EXECUTABLE%" start %CMD_LINE_ARGS%
:end
catalina.bat (bootstrap.jar)
if "%CLASSPATH%" == "" goto emptyClasspath
set "CLASSPATH=%CLASSPATH%;"
:emptyClasspath
set "CLASSPATH=%CLASSPATH%%CATALINA_HOME%\bin\bootstrap.jar"
启动入口 Bootstrap.main

org.apache.catalina.startup.Bootstrap#main

public static void main(String args[]) {synchronized (daemonLock) {//执行init方法初始化,创建Catalina对象bootstrap.init();//...String command = "start";//...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);} else if (command.equals("configtest")) {daemon.load(args);if (null == daemon.getServer()) {System.exit(1);}System.exit(0);}}
}

Bootstrap初始化组件

解析配置xml :org.apache.catalina.startup.Catalina#parseServerXml

初始化Bootstrap – bootstrap.init
  • 初始化ClassLoader
  • 通过反射创建Catalina(反射解耦)
public void init() throws Exception {//初始化ClassLoaderinitClassLoaders();Thread.currentThread().setContextClassLoader(catalinaLoader);SecurityClassLoad.securityClassLoad(catalinaLoader);//使用自定义ClassLoader类加载器 反射创建CatalinaClass<?> startupClass = catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");Object startupInstance = startupClass.getConstructor().newInstance();String methodName = "setParentClassLoader";Class<?> paramTypes[] = new Class[1];paramTypes[0] = Class.forName("java.lang.ClassLoader");Object paramValues[] = new Object[1];paramValues[0] = sharedLoader;//反射获取Catalina的setParentClassLoaderMethod method = startupInstance.getClass().getMethod(methodName, paramTypes);//设置父ClassLoadermethod.invoke(startupInstance, paramValues);catalinaDaemon = startupInstance;
}因为Bootstrap这个类在Tomcat打包发布时是放在bin\bootstrap.jar中,
而Catalina类是放在lib\catalina.jar中,两个jar是用不同的ClassLoader加载的,
所以不能在Bootstrap类中直接引用Catalina类,只能通过反射。
加载Bootstrap – daemon.load(args)
  • 执行Bootstrap的load方法
  • 反射调用Catalina的load方法
private void load(String[] arguments) throws Exception {String methodName = "load";//....//获取Catalina的load方法Method method = catalinaDaemon.getClass().getMethod(methodName, paramTypes);//通过反射调用Catalina.load方法method.invoke(catalinaDaemon, param);
}
加载Catalina – Catalina.load
  • 执行初始化
  • 解析server.xml配置文件–parseServerXml
    – 创建启动或者停止的xml解析器Digester
  • 创建Server
  • 初始化Server
public void load() {//执行初始化initDirs();initNaming();//解析server.xml配置文件parseServerXml(true);//创建ServerServer s = getServer();//初始化ServergetServer().init();
}// 解析server.xml
protected void parseServerXml(boolean start) {//....try (ConfigurationSource.Resource resource = ConfigFileLoader.getSource().getServerXml()) {//创建启动或者停止的xml解析器DigesterDigester digester = start ? createStartDigester() : createStopDigester();//....} catch (Exception e) {log.warn(sm.getString("catalina.configFail", file.getAbsolutePath()), e);if (file.exists() && !file.canRead()) {log.warn(sm.getString("catalina.incorrectPermissions"));}}
}
初始化Server – Lifecycle.init()
  • 调用抽象方法,执行具体实现,初始化
  • 模板方法模式
  • 执行实现的StandardServer.initInternal方法初始化Server
  • 循环初始化Service
public final synchronized void init() throws LifecycleException {if (!state.equals(LifecycleState.NEW)) {invalidTransition(Lifecycle.BEFORE_INIT_EVENT);}try {setStateInternal(LifecycleState.INITIALIZING, null, false);//调用抽象方法,执行具体实现,初始化initInternal();setStateInternal(LifecycleState.INITIALIZED, null, false);} catch (Throwable t) {handleSubClassException(t, "lifecycleBase.initFail", toString());}
}protected void initInternal() throws LifecycleException {super.initInternal();//初始化reconfigureUtilityExecutor(getUtilityThreadsInternal(utilityThreads));register(utilityExecutor, "type=UtilityExecutor");onameStringCache = register(new StringCache(), "type=StringCache");// Register the MBeanFactoryMBeanFactory factory = new MBeanFactory();factory.setContainer(this);onameMBeanFactory = register(factory, "type=MBeanFactory");globalNamingResources.init();//循环初始化Servicefor (Service service : services) {service.init();}
}
初始化Service – service.init
  • 同初始化Server,模板方法调用 Lifecycle.init()
  • 调用StandardService.initInternal方法
  • 初始化Engine引擎
  • 初始化Executor线程连接池
    ○ tomcat线程池与jdk线程池区别
    ○ tomcat自定义TaskQueue, 默认队列大小是无限大队列,
    ○ tomcat重写了offer入队方法,
    ○ 如果线程池线程数量小于线程池最大线程池,则入队失败(会直接开启非核心线程接收请求,而非入队)
  • 初始化监听器
  • 初始化Connector连接器
protected void initInternal() throws LifecycleException {super.initInternal();//初始化Engine引擎if (engine != null) {engine.init();}//初始化Executor线程池for (Executor executor : findExecutors()) {if (executor instanceof JmxEnabled) {((JmxEnabled) executor).setDomain(getDomain());}executor.init();}// 初始化监听器mapperListener.init();//初始化Connector连接器synchronized (connectorsLock) {for (Connector connector : connectors) {connector.init();}}
}
初始化Connector – Connector.initInternal
  • 初始化CoyoteAdapter适配器
  • 初始化ProtocolHandler
protected void initInternal() throws LifecycleException {// 初始化CoyoteAdapteradapter = new CoyoteAdapter(this);protocolHandler.setAdapter(adapter);//....//初始化ProtocolHandlerprotocolHandler.init();
}
初始化ProtocolHandler
  • 初始化EndPoint
public void init() throws Exception {//....String endpointName = getName();endpoint.setName(endpointName.substring(1, endpointName.length()-1));endpoint.setDomain(domain);//初始化EndPointendpoint.init();
}
初始化EndPoint – AbstractEndpoint.init
  • 绑定Servlet
  • 注册EndPoint
public final void init() throws Exception {if (bindOnInit) {//绑定Servlet相关能力bindWithCleanup();bindState = BindState.BOUND_ON_INIT;}if (this.domain != null) {// 注册EndPointoname = new ObjectName(domain + ":type=ThreadPool,name=\"" + getName() + "\"");Registry.getRegistry(null, null).registerComponent(this, oname, null);ObjectName socketPropertiesOname = new ObjectName(domain + ":type=SocketProperties,name=\"" + getName() + "\"");socketProperties.setObjectName(socketPropertiesOname);Registry.getRegistry(null, null).registerComponent(socketProperties, socketPropertiesOname, null);for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {registerJmx(sslHostConfig);}}
}
绑定Servlet
  • 初始化ServerSocket
  • 初始化SSL
public void bind() throws Exception {//初始化ServerSocketinitServerSocket();setStopLatch(new CountDownLatch(1));//初始化SSLinitialiseSsl();selectorPool.open(getName());
}//初始化ServerSocket
protected void initServerSocket() throws Exception {if (!getUseInheritedChannel()) {serverSock = ServerSocketChannel.open();socketProperties.setProperties(serverSock.socket());InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());serverSock.socket().bind(addr,getAcceptCount());} else {Channel ic = System.inheritedChannel();if (ic instanceof ServerSocketChannel) {serverSock = (ServerSocketChannel) ic;}if (serverSock == null) {throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited"));}}serverSock.configureBlocking(true); //mimic APR behavior
}

Bootstrap启动

启动Bootstrap – bootstrap.start
  • 如果没有初始化,则在此初始化
  • 反射调用Catalina的start方法
public void start() throws Exception {//如果没有初始化,则在此初始化if (catalinaDaemon == null) {init();}//反射调用Catalina的start方法Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);method.invoke(catalinaDaemon, (Object [])null);
}
启动Catalina.start
  • 启动Server
  • 启动失败则销毁Server
public void start() {//启动Servertry {getServer().start();} catch (LifecycleException e) {try {//启动失败则销毁getServer().destroy();} catch (LifecycleException e1) {log.debug("destroy() failed for failed Server ", e1);}return;}if (generateCode) {// Generate loader which will load all generated classesgenerateLoader();}// Register shutdown hookif (useShutdownHook) {if (shutdownHook == null) {shutdownHook = new CatalinaShutdownHook();}Runtime.getRuntime().addShutdownHook(shutdownHook);LogManager logManager = LogManager.getLogManager();if (logManager instanceof ClassLoaderLogManager) {((ClassLoaderLogManager) logManager).setUseShutdownHook(false);}}if (await) {await();stop();}
}
启动Server – Lifecycle.start
  • 调用抽象方法,执行具体实现,初始化
  • 模板方法模式
  • 执行实现的StandardServer.startInternal方法启动Server
  • 循环启动Service

public final synchronized void start() throws LifecycleException {//....setStateInternal(LifecycleState.STARTING_PREP, null, false);//startInternal();}protected void startInternal() throws LifecycleException {//循环启动servicesynchronized (servicesLock) {for (Service service : services) {service.start();}}if (periodicEventDelay > 0) {monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(new Runnable() {@Overridepublic void run() {startPeriodicLifecycleEvent();}}, 0, 60, TimeUnit.SECONDS);}
}
启动Service – StandardService.startInternal
  • 启动Engine引擎
  • 启动Executor线程连接池
  • 启动监听器
  • 启动Connector连接器
protected void startInternal() throws LifecycleException {// 启动Engine引擎if (engine != null) {synchronized (engine) {engine.start();}}//启动Executor线程连接池synchronized (executors) {for (Executor executor: executors) {executor.start();}}//启动监听器mapperListener.start();//启动Connector连接器synchronized (connectorsLock) {for (Connector connector: connectors) {if (connector.getState() != LifecycleState.FAILED) {connector.start();}}}
}
启动Connector – Connector.startInternal
  • 设置状态
  • 启动ProtocolHandler
protected void startInternal() throws LifecycleException {//设置状态setState(LifecycleState.STARTING);//启动ProtocolHandlerprotocolHandler.start();
}
启动ProtocolHandler – AbstractProtocol.start
public void start() throws Exception {//启动Endpointendpoint.start();monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(new Runnable() {@Overridepublic void run() {if (!isPaused()) {startAsyncTimeout();}}}, 0, 60, TimeUnit.SECONDS);
}
启动Endpoint
  • 初始化连接
  • 启动接收的线程
public final void start() throws Exception {if (bindState == BindState.UNBOUND) {bindWithCleanup();bindState = BindState.BOUND_ON_START;}startInternal();
}public void startInternal() throws Exception {//初始化连接initializeConnectionLatch();//启动接收的线程startAcceptorThread();
}
Acceptor接收器 – socket.accept
  • 实现Runnable
  • run方法接收客户端请求
  • socket.accept监听接收客户端请求
public class Acceptor<U> implements Runnable {@Overridepublic void run() {//接收客户端请求socket = endpoint.serverSocketAccept();}
}
//socket.accept监听接收客户端请求
protected SocketChannel serverSocketAccept() throws Exception {return serverSock.accept();
}

参考资源: Java进阶教程Tomcat核心原理解析


http://chatgpt.dhexx.cn/article/teRTAjHE.shtml

相关文章

Tomcat服务器的安装和启动

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 安装一、从Tomcat官网下载解压二、Tomcat启动1.启动2.诊断 总结 安装 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 目前Tomcat的最新版本是To…

C++11新特性之nullptr

在C11之前的C98/03我们使用空都是NULL关键字&#xff0c;后来C11之后新增了nullptr关键字来表示空。那么有了NULL还要弄个nullptr出来干什么呢&#xff1f;是不是吃太饱了&#xff1f; 为了来剖析这两者的区别&#xff0c;我们先来看一个什么是野指针&#xff1b; int serven_…

C语言nullptr错误,c/c++中的NULL,nullptr,0

NULL,nullptr与0 0 NULL C语言中 C++中 隐式类型转换 nullptr 预处理中的条件编译语句 0 在我们的程序中,单纯一个0,在不同的类型中有着不同的意思 0,是一个空字符常量,他在ASCII中的序号就是0,是一个字符串的结束标准 ‘0’,表示一个字符0,他在ASCII中的序号是48 “0”…

C语言nullptr错误,C ++中的nullptr到底是什么

对于有经验的C ++和那些了解现代C ++编程语言的人来说,C ++中的nullptr到底是什么,这将是非常简单的问题。但是nullptr不仅是C ++中的编程语言,而且为了解释这一点,我们先了解一下NULL的问题,然后我们将深入研究nullptr的简单实现以及nullptr的一些用例。为什么我们需要nu…

C++中NULL和nullptr的区别

在编写C程序的时候只看到过NULL&#xff0c;而在C的编程中&#xff0c;我们可以看到NULL和nullptr两种关键字&#xff0c;其实nullptr是C11版本中新加入的&#xff0c;它的出现是为了解决NULL表示空指针在C中具有二义性的问题&#xff0c;为了弄明白这个问题&#xff0c;我查找…

C++11中的nullptr

一、什么是nullptr&#xff1f; nullptr是c11的空指针&#xff0c;可以理解为 NULL的升级版。 二、解决什么问题&#xff1f; 首先&#xff0c;在C语言中&#xff0c;NULL是被定义成这样的#define NULL ((void *)0)。 而C中&#xff0c;NULL是被定义成这样#define NULL 0。 …

C++基础:指针空值(nullptr)

初始化指针是将其指向一个“空”位置&#xff0c;比如0。由于大多数计算机系统不允许用户程序写地址为0的内存空间&#xff0c;倘若程序无意中对该指针所指地址赋值&#xff0c;通常在运行时就会导致程序退出。虽然程序退出并非什么好事&#xff0c;但这样一来错误也容易被程序…

【Kafka】消息的同步发送和异步发送

文章目录 概述1. sync vs async1.1 java代码同步和异步 2. 可靠性机制(ack属性配置)2.1 oneway 3. 一般配置4. 同步异步和ack的联系和区别参考 概述 kafka有同步&#xff08;sync&#xff09;、异步&#xff08;async&#xff09;以及oneway这三种发送方式&#xff0c;某些概念…

http请求与响应,同步异步请求以及异步请求axios的配置

文章目录 httphttp简介&#xff0c;协议http请求http响应接收请求行请求头数据 同步异步请求异步请求axios的配置配置文件 http http简介&#xff0c;协议 http是超文本传输协议 &#xff08;HyperText Transfer Protocol&#xff09;服务器传输超文本 到本地浏览器的传送协议…

ajax同步和异步的区别

一、同步访问和异步访问的区别&#xff0c;先从概念上区别&#xff1a; 1、同步的概念应该是来自于操作系统中关于同步的概念。 2、不同进程为协同完成某项工作而在先后次序上调整(通过阻塞,唤醒等方式)。同步强调的是顺序性&#xff0c;谁先谁后&#xff1b;异步则不存在这种顺…

C++ LinuxWebServer项目(5)同步异步日志系统

一、前言 对于任何一个服务器而言,日志系统的设计是非常重要的,尝试设计一个简易的同步异步日志系统来完成系统日志的记录。 二、基础知识 日志,由服务器自动创建,并记录运行状态,错误信息,访问数据的文件。 同步日志,日志写入函数与工作线程串行执行,由于涉及到I…

一文搞懂同步异步阻塞非阻塞

相信很多人在面试的过程中&#xff0c;都被问到过同步和异步的区别、阻塞和非阻塞的区别&#xff0c;以及这两对关系又有什么联系&#xff1f;本文尽可能从专业的角度&#xff0c;用易懂的语言&#xff0c;帮助大家理解 01 前置知识 用户空间和内核空间 操作系统可以支持多个…

同步异步半同步分离式通信

同步通信&#xff1a;采用统一的时钟信号 读数据 T1上升沿主设备给出从设备地址 T2上升沿给出读命令 T3上升沿读数据 T4上升沿撤销 写数据 T1上升沿主设备给出从设备地址 T1下降沿给出数据 T2上升沿给写命令 T4上升沿撤销 异步通信分为三类&#xff1a; 不互锁&#…

一篇文章理解 同步异步、阻塞非阻塞

前述 同步异步&#xff0c;阻塞非阻塞是一些非常常见的概念&#xff0c;但是对于开发者来说往往是用到了很难说清楚。 笔者专门整理了下这方面的概念&#xff0c;作此文以记之。 这部分内容可能存在一些争议&#xff0c;如有不同意见欢迎评论交流。 概念 个人理解同步异步与阻…

ES6同步异步处理

同步和异步 1.同步就是代码从上而下依次执行&#xff0c;除了函数或则回调函数 2.异步也有先后之分但是不明显&#xff0c;等js代码先执行同步后再去执行异步的代码. 如何处理同步异步的问题&#xff08;ES6的Promise&#xff09; 接上面&#xff0c;看下面的代码 var arr[…

前端学习-同步异步问题

在做实作课作品时&#xff0c;出现过对象中变量访问不到的情况&#xff0c;查阅相关资料发现时同步异步的问题&#xff0c;这篇文章帮助我理清思路&#xff0c;希望也能帮助你们更好地理解同步异步。 一、什么是同步/异步任务&#xff1f; 同步任务&#xff1a;指的是在主线程…

dubbo同步异步调用

通常我们通过dubbo调用服务接口&#xff0c;等待提供方处理完响应结果&#xff0c;这是同步调用&#xff1b;也是默认的调用方式。通过查看原吗DubboInvoker可以看到&#xff1a; 整体来说有三种方式&#xff1a; 1、是否关注结果&#xff0c;returntrue关注&#xff0c;默认也…

理解:什么是同步和异步?什么是阻塞和非阻塞?

一、同步和异步 同步与异步是指访问数据的机制&#xff0c;同步一般指主动请求并等待IO操作完成的方式。 异步则指主动请求数据后便可以继续处理其它任务&#xff0c;随后等待IO操作完毕的通知。 同步和异步最大的区别就在于&#xff1a;同步需要等待&#xff0c;异步不需要等…

CPUGPU加速计算

1、CPU(Centrol Processing Unit) CPU上的大部分面积做了cache 和控制逻辑&#xff0c;天然适合做复杂串行程序&#xff1b; 2、GPU(Graphic Processing Unit): GPU有更多的晶体管用于数据处理&#xff0c;特别适用于解决并行计算的问题。可以使程序执行速度加快。为处理图形…

tensorflow使用GPU加速

测试faster-rcnn时&#xff0c;cpu计算速度较慢&#xff0c;调整代码改为gpu加速运算 将 with tf.Session() as sess: 替换为 1 gpu_options tf.GPUOptions(per_process_gpu_memory_fraction0.9) 2 with tf.Session(configtf.ConfigProto(gpu_optionsgpu_options,log_device_…