广告位联系
返回顶部
分享到

Tomcat启动核心流程介绍

Tomcat 来源:互联网 作者:佚名 发布时间:2022-08-20 08:32:08 人浏览
摘要

一、Tomcat的启动核心流程 前面给大家介绍了Tomcat中的生命周期的设计,掌握了这块对于我们分析Tomcat的核心流程是非常有帮助的,也就是我们需要创建相关的核心组件,比如Server,Se

一、Tomcat的启动核心流程

前面给大家介绍了Tomcat中的生命周期的设计,掌握了这块对于我们分析Tomcat的核心流程是非常有帮助的,也就是我们需要创建相关的核心组件,比如Server,Service肯定都绕不开生命周期的方法。

1.启动的入口

你可以通过脚本来启动Tomcat服务(startup.bat),但如果你看过脚本的命令,你会发现最终调用的还是Bootstrap中的main方法,所以我们需要从main方法来开始

然后我们去看main方法中的代码,我们需要重点关注的方法有三个

  • bootstrap.init()方法
  • load()方法
  • start()方法

也就是在这三个方法中会完成Tomcat的核心操作。

2.init方法

我们来看下init方法中的代码,非核心的我们直接去掉

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

public void init() throws Exception {

    // 创建相关的类加载器

    initClassLoaders();

    // 省略部分代码...

    // 通过反射创建了 Catalina 类对象

    Class<?> startupClass = catalinaLoader

        .loadClass("org.apache.catalina.startup.Catalina");

    // 创建了 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;

    // 把 sharedLoader 设置为了 commonLoader的父加载器

    Method method =

        startupInstance.getClass().getMethod(methodName, paramTypes);

    method.invoke(startupInstance, paramValues);

    // Catalina 实例 赋值给了 catalinaDaemon

    catalinaDaemon = startupInstance;

}

  • 首先是调用了initClassLoaders()方法,这个方法会完成对应的ClassLoader的创建,这个比较重要,后面专门写一篇文章来介绍。
  • 通过反射的方式创建了Catalina的类对象,并通过反射创建了Catalina的实例
  • 设置了类加载器的父子关系
  • 用过成员变量catalinaDaemon记录了我们创建的Catalina实例

这个是通过bootstrap.init()方法我们可以获取到的有用的信息。然后我们继续往下面看。

3.load方法

然后我们来看下load方法做了什么事情,代码如下:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

private void load(String[] arguments) throws Exception {

    // Call the load() method

    String methodName = "load"; // load方法的名称

    Object param[];

    Class<?> paramTypes[];

    if (arguments==null || arguments.length==0) {

        paramTypes = null;

        param = null;

    } else {

        paramTypes = new Class[1];

        paramTypes[0] = arguments.getClass();

        param = new Object[1];

        param[0] = arguments;

    }

    // catalinaDaemon 就是在 init中创建的 Catalina 对象

    Method method =

        catalinaDaemon.getClass().getMethod(methodName, paramTypes);

    if (log.isDebugEnabled()) {

        log.debug("Calling startup class " + method);

    }

    // 会执行 Catalina的load方法

    method.invoke(catalinaDaemon, param);

}

上面的代码非常简单,通过注释我们也可以看出该方法的作用是调用 Catalina的load方法。所以我们还需要加入到Catalina的load方法中来查看,代码同样比较长,只留下关键代码

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

public void load() {

    if (loaded) {

        return; // 只能被加载一次

    }

    loaded = true;

    initDirs(); // 废弃的方法

    // Before digester - it may be needed

    initNaming(); // 和JNDI 相关的内容 忽略

    // Create and execute our Digester

    // 创建并且执行我们的 Digester 对象  Server.xml

    Digester digester = createStartDigester();

    // 省略掉了 Digester文件处理的代码

    getServer().setCatalina(this); // Server对象绑定 Catalina对象

    getServer().setCatalinaHome(Bootstrap.getCatalinaHomeFile());

    getServer().setCatalinaBase(Bootstrap.getCatalinaBaseFile());

    // Stream redirection

    initStreams();

    // 省略掉了部分代码...

     getServer().init(); // 完成 Server  Service Engine Connector等组件的init操作

}

把上面的代码简化后我们发现这个Load方法其实也是蛮简单的,就做了两件事。

  • 通过Apache下的Digester组件完成了Server.xml文件的解析
  • 通过getServer().init() 方法完成了Server,Service,Engin,Connector等核心组件的初始化操作,这块和前面的LifecycleBase呼应起来了。

如果生命周期的内容不清楚,请看前面内容介绍

4.start方法

最后我们来看下start方法的代码。

1

2

3

4

5

6

7

8

9

public void start() throws Exception {

    if (catalinaDaemon == null) {

        init(); // 如果 catalinaDaemon 为空 初始化操作

    }

    // 获取的是 Catalina 中的 start方法

    Method method = catalinaDaemon.getClass().getMethod("start", (Class [])null);

    // 执行 Catalina 的start方法

    method.invoke(catalinaDaemon, (Object [])null);

}

上面的代码逻辑也很清楚,就是通过反射的方式调用了Catalina对象的start方法。所以进入Catalina的start方法中查看。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

public void start() {

    if (getServer() == null) {

        load(); // 如果Server 为空 重新 init 相关的组件

    }

    if (getServer() == null) {

        log.fatal("Cannot start server. Server instance is not configured.");

        return;

    }

    // Start the new server  关键方法---&gt;启动Server

    try {

        getServer().start();

    } catch (LifecycleException e) {

        // 省略...

    }

    // 省略...

    // Register shutdown hook  注册关闭的钩子

    if (useShutdownHook) {

        // 省略...

    }

    if (await) {

        await();

        stop();

    }

}

通过上面的代码我们可以发现核心的代码还是getServer.start()方法,也就是通过Server对象来嵌套的调用相关注解的start方法。

5.核心流程的总结

我们可以通过下图来总结下Tomcat启动的核心流程

从图中我们可以看到Bootstrap其实没有做什么核心的事情,主要还是Catalina来完成的。


版权声明 : 本文内容来源于互联网或用户自行发布贡献,该文观点仅代表原作者本人。本站仅提供信息存储空间服务和不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权, 违法违规的内容, 请发送邮件至2530232025#qq.cn(#换@)举报,一经查实,本站将立刻删除。
原文链接 : https://juejin.cn/post/7132710433475002405
相关文章
  • 本站所有内容来源于互联网或用户自行发布,本站仅提供信息存储空间服务,不拥有版权,不承担法律责任。如有侵犯您的权益,请您联系站长处理!
  • Copyright © 2017-2022 F11.CN All Rights Reserved. F11站长开发者网 版权所有 | 苏ICP备2022031554号-1 | 51LA统计