当前位置: 代码网 > 服务器>服务器>Tomcat > Tomcat启动核心流程示例详解

Tomcat启动核心流程示例详解

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

一、tomcat的启动核心流程

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

1.启动的入口

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

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

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

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

2.init方法

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

    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方法做了什么事情,代码如下:

    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方法中来查看,代码同样比较长,只留下关键代码

    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方法的代码。

    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方法中查看。

    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来完成的。

以上就是tomcat启动核心流程示例详解的详细内容,更多关于tomcat启动流程的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com