Tomcat源码解析-启动过程分析之主干流程
找到catalina.sh脚本路径,将启动参数传递给catalina.sh执行。
catalina.sh start 最终会执行org.apache.catalina.startup.Bootstrap中的main方法,并把start参数传入。
以后分析Tomcat关闭的时候,也是一个套路,最终都会调用到org.apache.catalina.startup.Bootstrap的main方法,并把stop参数传入。
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
/** * 通过提供的脚本启动Tomcat时的主方法和入口点。 * * @param args 要处理的命令行参数 */ public static void main(String args[]) { //main使用的守护进程对象。 synchronized (daemonLock) { //daemon是volatile修饰的Bootstrap对象 if (daemon == null) { //在init()完成之前不要设置守护进程 Bootstrap bootstrap = new Bootstrap(); try { //初始化守护进程。 bootstrap.init(); } catch (Throwable t) { handleThrowable(t); t.printStackTrace(); return; } daemon = bootstrap; } else { // W当作为服务运行时,要停止的调用将位于新线程上, // 因此请确保使用了正确的类加载器,以防止出现一系列类未找到异常。直到init()完成 Thread.currentThread().setContextClassLoader(daemon.catalinaLoader); } } 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")) { //启动操作 //通过反射调用守护进程引用的org.apache.catalina.startup.Catalina实例的setAwait方法 daemon.setAwait(true); //调用Catalina实例的load方法 daemon.load(args); //start方法 daemon.start(); //反射调用Catalina实例的getServer方法,返回的对象为空时,终止当前运行的Java虚拟机。 if (null == daemon.getServer()) { System.exit(1); } } else if (command.equals("stop")) { //通过反射调用Catalina的stopServer方法。 daemon.stopServer(args); } else if (command.equals("configtest")) { daemon.load(args); if (null == daemon.getServer()) { System.exit(1); } System.exit(0); } else { log.warn("Bootstrap: command \"" + command + "\" does not exist."); } } catch (Throwable t) { // Unwrap the Exception for clearer error reporting if (t instanceof InvocationTargetException && t.getCause() != null) { t = t.getCause(); } handleThrowable(t); t.printStackTrace(); System.exit(1); } } |
1、初始化守护进程,获取类加载器和反射实例化org.apache.catalina.startup.Catalina。
2、根据启动参数start,通过反射,依次执行Catalina实例的setAwait、load、start方法。
1 setAwait
|
1
2
3
4
5
6
7
8
|
/** * Use await. */ protected boolean await = false; public void setAwait(boolean b) { await = b; } |
2 load
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
|
/** * 启动一个新的服务器实例。 */ public void load() { //防止重复加载。 if (loaded) { return; } loaded = true; long t1 = System.nanoTime(); //创建java.io.tmpdir文件夹 initDirs(); // Before digester - it may be needed //初始化jmx的环境变量 initNaming(); // Create and execute our Digester //创建和配置将用于启动的Digester。 //配置解析server.xml中各个标签的解析类 Digester digester = createStartDigester(); InputSource inputSource = null; InputStream inputStream = null; File file = null; try { //下面一大段都是为了加载conf/server.xml配置文件,失败就加载server-embed.xml ... try { inputSource.setByteStream(inputStream); //把Catalina作为一个顶级容器 digester.push(this); //解析过程会实例化各个组件,比如Server、Container、Connector等 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 } } } //这里的server在解析xml之后就有值了,这是Server的Catalina信息 getServer().setCatalina(this); getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile()); getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile()); // Stream redirection initStreams(); // Start the new server try { //生命周期init方法 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"); } } |
- 初始化JMX环境变量
- 创建和配置Digester
- 读取配置文件conf/server.xml配置文件,失败就加载server-embed.xml
- 通过Digester解析配置文件,并将当前Catalina作为最顶层容器,解析过程会实例化各种组件
- 设置Server组件的catalina信息
- 调用Server组件的生命周期init方法
下面看start方法:
3 start
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
|
/** * 启动一个新的服务器实例。 */ public void start() { //如果Server组件不存在,则重新执行load方法 if (getServer() == null) { load(); } //依然不存在就返回 if (getServer() == null) { log.fatal("Cannot start server. Server instance is not configured."); return; } long t1 = System.nanoTime(); // Start the new server try { //调用Server的start方法 getServer().start(); } catch (LifecycleException e) { log.fatal(sm.getString("catalina.serverStartFail"), e); try { //异常的时候调用Server的destroy方法 getServer().destroy(); } catch (LifecycleException e1) { log.debug("destroy() failed for failed Server ", e1); } return; } long t2 = System.nanoTime(); if (log.isInfoEnabled()) { log.info("Server startup in " + ((t2 - t1) / 1000000) + " ms"); } // Register shutdown hook //注册关闭钩子 if (useShutdownHook) { if (shutdownHook == null) { // Catalina.this.stop(); shutdownHook = new CatalinaShutdownHook(); } Runtime.getRuntime().addShutdownHook(shutdownHook); // If JULI is being used, disable JULI's shutdown hook since // shutdown hooks run in parallel and log messages may be lost // if JULI's hook completes before the CatalinaShutdownHook() LogManager logManager = LogManager.getLogManager(); if (logManager instanceof ClassLoaderLogManager) { ((ClassLoaderLogManager) logManager).setUseShutdownHook( false); } } // Bootstrap中会设置await为true,其目的在于让tomcat在shutdown端口阻塞监听关闭命令 if (await) { //等待收到正确的关机命令,然后返回。 await(); //停止现有的服务器实例。 stop(); } } |
- 调用Server组件的start方法,开启一个新的服务。
- 注册关闭钩子
- 让Tomcat在shutdown端口阻塞监听关闭命令
其中的load方法中的解析配置文件与注册组件、执行生命周期方法init;
start方法中的开启服务、注册关闭钩子、阻塞监听关闭指令等详细细节,将在后期慢慢分析。
Tomcat源码解析-启动过程分析之主干流程的更多相关文章
- 渣渣菜鸡的 ElasticSearch 源码解析 —— 启动流程(下)
关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/08/12/es-code03/ 前提 上篇文章写完了 ES 流程启动的一部分,main 方法都入 ...
- 渣渣菜鸡的 ElasticSearch 源码解析 —— 启动流程(上)
关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/08/11/es-code02/ 前提 上篇文章写了 ElasticSearch 源码解析 -- ...
- Tomcat源码分析——启动与停止服务
前言 熟悉Tomcat的工程师们,肯定都知道Tomcat是如何启动与停止的.对于startup.sh.startup.bat.shutdown.sh.shutdown.bat等脚本或者批处理命令,大家 ...
- Tomcat源码解析-整体流程介绍
一.架构 下面谈谈我对Tomcat架构的理解 总体架构: 1.面向组件架构 2.基于JMX 3.事件侦听 1)面向组件架构 tomcat代码看似很庞大,但从结构上看却很清晰和简单,它主要由一堆组件组成 ...
- Okhttp3源码解析(3)-Call分析(整体流程)
### 前言 前面我们讲了 [Okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [Okhttp3源码解析(1)-OkHttpClient分析]( ...
- TOMCAT源码分析(启动框架)
建议: 毕竟TOMCAT的框架还是比较复杂的, 单是从文字上理解, 是不那么容易掌握TOMCAT的框架的. 所以得实践.实践.再实践. 建议下载一份TOMCAT的源码, 调试通过, 然后单步跟踪其启动 ...
- 分布式事务_02_2PC框架raincat源码解析-启动过程
一.前言 上一节已经将raincat demo工程运行起来了,这一节来分析下raincat启动过程的源码 主要包括: 事务协调者启动过程 事务参与者启动过程 二.协调者启动过程 主要就是在启动类中通过 ...
- 【Android】Android 4.0 Launcher2源码分析——启动过程分析
Android的应用程序的入口定义在AndroidManifest.xml文件中可以找出:[html] <manifest xmlns:android="http://schemas. ...
- 【转】Android 4.0 Launcher2源码分析——启动过程分析
Android的应用程序的入口定义在AndroidManifest.xml文件中可以找出:[html] <manifest xmlns:android="http://schemas. ...
随机推荐
- mysql my.cnf常用的配置
[mysqld]basedir = /usr/local/mysql/datadir = /usr/local/mysql/dataport = 3306pid-file = /usr/local/m ...
- Mac系统的SVN客户端:Snail SVN 精简版
Mac系统的SVN客户端:Snail SVN 精简版 前言 本人在公司中,使用的是windows操作系统,svn客户端自然也就使用tortoise svn.但自从男朋友给我买了台macbook pro ...
- Java线程(一)——创建线程的两种方法
Thread 和 Runnable Java程序是通过线程执行的,线程在程序中具有独立的执行路径.当多条线程执行时,它们之间的路径可以不同,例如,一条线程可能在执行switch的一个case语句,另一 ...
- Deep-Learning-with-Python] 文本序列中的深度学习
https://blog.csdn.net/LSG_Down/article/details/81327072 将文本数据处理成有用的数据表示 循环神经网络 使用1D卷积处理序列数据 深度学习模型可以 ...
- thrift生成c++服务端和客户端
https://blog.csdn.net/jdx0909/article/details/84727523 https://blog.csdn.net/luoyexuge/article/detai ...
- object detection模型转换成TensorFlow Lite,在Android应用
环境 tensorflow = 1.12.0 bazel = 0.18.1 ubuntu = 16.04 python = 3.6.2 安装 bazel (0.18.1) 如果tensorflow是1 ...
- Django专题之ORM操作2
Django ORM操作 目录 一般操作 看专业的官网文档,做专业的程序员! 回到顶部 必知必会13条 <1> all(): 查询所有结果 <2> get(**kwargs ...
- Oracle存储过程案例集合
注:使用的工具为PLSQL Developer 壹.while简单使用(替换字符串中的字符,和REPLACE效果一样) 注: 这里没有使用REPLACE函数 1.建立存储过程 CREATE OR RE ...
- ubuntu18安装pytorch1.3
环境: ubuntu18 anaconda 创建一个新的环境 conda create -n env_name python=version 激活并进入环境中 conda activate env_n ...
- Matlab高级教程_第一篇:Matlab基础知识提炼_02
第三节:变量 正如其他编程软件一样. 都是通过变量来传递和交换数据的,这是基础.按照<MATLAB基础知识提炼>这篇文章先介绍变量比较合适.编程语言不外乎包括两部分:数据和结构.应该先把数 ...