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--SHOW ENGINE INNODB STATUS
===================================== -- :: 0x7f305b965700 INNODB MONITOR OUTPUT =================== ...
- frp内网穿透,centos7+frp成功样例
准备工作: 阿里云服务器一台,备案域名一个,本地服务器一台(本人用的虚拟机centos7) frp文件:frp_0.22.0_linux_amd64.tar.gz 链接:https://pan.bai ...
- IO流的学习以及统计次数最多的单词
IO流: 处理数据类型:字节流(InputStream OutputStream)和字节流(Reader Writer) 数据流向不同:输入流和输出流(FileInputStream File ...
- CodeForces 1294B Collecting Packages(排序+贪心)
http://codeforces.com/contest/1294/problem/B 大致题意: 一张图上有n个包裹,给出他们的坐标,一个机器人从(0,0)出发,只能向右(R)或向上(U),问能否 ...
- EXCEL快速实现下拉计算快捷键
ctrl + shift + 方向键,,选择要填充的范围,,然后ctrl + d
- 编程作业1.1——sklearn机器学习算法系列之LinearRegression线性回归
知识点 scikit-learn 对于线性回归提供了比较多的类库,这些类库都可以用来做线性回归分析. 我们也可以使用scikit-learn的线性回归函数,而不是从头开始实现这些算法. 我们将scik ...
- 连词词组|relax|brings about a rise in|Chance are (high)that|Have no clue|Be passionate about|Tedious|overwhelmed by piles of
efficient有效率的 effective有效果的 Make sb. Do Stuff没有复数 首先的三种表述:First off=To begin with=For starters 其次:Ad ...
- gcc -E xx.c
C语言代码在交给编译器之前,会先由预处理器进行一些文本替换方面的操作,例如宏展开.文件包含.删除部分代码等. 在正常的情况下,GCC 不会保留预处理阶段的输出文件,也即.i文件.然而,可以利用-E选项 ...
- iTOP-4412开发板-can测试工具使用文档
本文档介绍如何使用 can 工具测试 can. 给用户提供了“can_libs.rar”以及“can_tools.zip”压缩包,分别是 can 工具需要的库 文件和 can 工具二进制文件. 注意开 ...
- 论文翻译——Recursive Deep Models for Semantic Compositionality Over a Sentiment Treebank
Abstract Semantic word spaces have been very useful but cannot express the meaning of longer phrases ...