Tomcat启动入口就在脚本startup.sh中,具体脚本可以看tomcat的源码,这个启动脚本主要用来判断环境,
找到catalina.sh脚本路径,将启动参数传递给catalina.sh执行。
catalina.sh start 最终会执行org.apache.catalina.startup.Bootstrap中的main方法,并把start参数传入。
以后分析Tomcat关闭的时候,也是一个套路,最终都会调用到org.apache.catalina.startup.Bootstrap的main方法,并把stop参数传入。
分析main方法:
[Java] 纯文本查看 复制代码
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方法。
下面主要分析Catalina实例的setAwait、load、start方法:

1 setAwait

入参为true
[Java] 纯文本查看 复制代码
1
2
3
4
5
6
7
8
/**
   * Use await.
   */
   protected boolean await = false;
 
   public void setAwait(boolean b) {
       await = b;
   }

2 load

[Java] 纯文本查看 复制代码
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方法
解析配置文件,注入catalina的各种组件后面分析。
下面看start方法:

3 start

[Java] 纯文本查看 复制代码
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端口阻塞监听关闭命令
本篇目的就是了解整个Tomcat启动的主干流程,体现在代码层的就是依次执行Catalina实例的setAwait、load、start方法。
其中的load方法中的解析配置文件与注册组件、执行生命周期方法init;
start方法中的开启服务、注册关闭钩子、阻塞监听关闭指令等详细细节,将在后期慢慢分析。
更多技术资讯可关注:itheimaGZ获取

Tomcat源码解析-启动过程分析之主干流程的更多相关文章

  1. 渣渣菜鸡的 ElasticSearch 源码解析 —— 启动流程(下)

    关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/08/12/es-code03/ 前提 上篇文章写完了 ES 流程启动的一部分,main 方法都入 ...

  2. 渣渣菜鸡的 ElasticSearch 源码解析 —— 启动流程(上)

    关注我 转载请务必注明原创地址为:http://www.54tianzhisheng.cn/2018/08/11/es-code02/ 前提 上篇文章写了 ElasticSearch 源码解析 -- ...

  3. Tomcat源码分析——启动与停止服务

    前言 熟悉Tomcat的工程师们,肯定都知道Tomcat是如何启动与停止的.对于startup.sh.startup.bat.shutdown.sh.shutdown.bat等脚本或者批处理命令,大家 ...

  4. Tomcat源码解析-整体流程介绍

    一.架构 下面谈谈我对Tomcat架构的理解 总体架构: 1.面向组件架构 2.基于JMX 3.事件侦听 1)面向组件架构 tomcat代码看似很庞大,但从结构上看却很清晰和简单,它主要由一堆组件组成 ...

  5. Okhttp3源码解析(3)-Call分析(整体流程)

    ### 前言 前面我们讲了 [Okhttp的基本用法](https://www.jianshu.com/p/8e404d9c160f) [Okhttp3源码解析(1)-OkHttpClient分析]( ...

  6. TOMCAT源码分析(启动框架)

    建议: 毕竟TOMCAT的框架还是比较复杂的, 单是从文字上理解, 是不那么容易掌握TOMCAT的框架的. 所以得实践.实践.再实践. 建议下载一份TOMCAT的源码, 调试通过, 然后单步跟踪其启动 ...

  7. 分布式事务_02_2PC框架raincat源码解析-启动过程

    一.前言 上一节已经将raincat demo工程运行起来了,这一节来分析下raincat启动过程的源码 主要包括: 事务协调者启动过程 事务参与者启动过程 二.协调者启动过程 主要就是在启动类中通过 ...

  8. 【Android】Android 4.0 Launcher2源码分析——启动过程分析

    Android的应用程序的入口定义在AndroidManifest.xml文件中可以找出:[html] <manifest xmlns:android="http://schemas. ...

  9. 【转】Android 4.0 Launcher2源码分析——启动过程分析

    Android的应用程序的入口定义在AndroidManifest.xml文件中可以找出:[html] <manifest xmlns:android="http://schemas. ...

随机推荐

  1. MySQL--SHOW ENGINE INNODB STATUS

    ===================================== -- :: 0x7f305b965700 INNODB MONITOR OUTPUT =================== ...

  2. frp内网穿透,centos7+frp成功样例

    准备工作: 阿里云服务器一台,备案域名一个,本地服务器一台(本人用的虚拟机centos7) frp文件:frp_0.22.0_linux_amd64.tar.gz 链接:https://pan.bai ...

  3. IO流的学习以及统计次数最多的单词

    IO流: 处理数据类型:字节流(InputStream  OutputStream)和字节流(Reader  Writer) 数据流向不同:输入流和输出流(FileInputStream   File ...

  4. CodeForces 1294B Collecting Packages(排序+贪心)

    http://codeforces.com/contest/1294/problem/B 大致题意: 一张图上有n个包裹,给出他们的坐标,一个机器人从(0,0)出发,只能向右(R)或向上(U),问能否 ...

  5. EXCEL快速实现下拉计算快捷键

    ctrl + shift + 方向键,,选择要填充的范围,,然后ctrl + d

  6. 编程作业1.1——sklearn机器学习算法系列之LinearRegression线性回归

    知识点 scikit-learn 对于线性回归提供了比较多的类库,这些类库都可以用来做线性回归分析. 我们也可以使用scikit-learn的线性回归函数,而不是从头开始实现这些算法. 我们将scik ...

  7. 连词词组|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 ...

  8. gcc -E xx.c

    C语言代码在交给编译器之前,会先由预处理器进行一些文本替换方面的操作,例如宏展开.文件包含.删除部分代码等. 在正常的情况下,GCC 不会保留预处理阶段的输出文件,也即.i文件.然而,可以利用-E选项 ...

  9. iTOP-4412开发板-can测试工具使用文档

    本文档介绍如何使用 can 工具测试 can. 给用户提供了“can_libs.rar”以及“can_tools.zip”压缩包,分别是 can 工具需要的库 文件和 can 工具二进制文件. 注意开 ...

  10. 论文翻译——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 ...