Tomcat的顶层结构及启动过程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/fan510988896/article/details/73603306

写在前面:

学习是什么?学习就是模仿,重复,实践,总结。

最近看的这本书里面有tomcat的简单源码部分,就研究一下,会有收获的。

这几天在看源码是用的是idea这款工具,几个月前还是挺抵触它的,感觉它没有eclipse好用,但是本着挑战未知领域的精神使用了3天,已经慢慢喜欢上这款工具了,推荐一下。

文章开始:

Server           服务器
Service          服务
Connector     连接器
Container      容器
顶层结构图:


Tomcat中最顶层的容器叫server,代表整个服务器,Server中至少包含一个Service,用于提供具体的服务。Service包含俩部分:container和connector。container用于封装和管理servlet,以及具体的request请求。Connector用于处理连接相关的事情,并提供Socket与request,response的转换。

它们之间的关系:(服务于服务器,server与service)

一个tomcat中只有一个server
一个server可以有多个service
一个service只有一个Container,但是可以有多个Connectors,因为一个服务可以有多个连接,如提供http和https连接,也可以提供相同协议不同端口的连接
Bootstrap是Tomcat的入口,正常情况下启动Tomcat就是调用Bootstrap的main方法

单词解释:
    catalina可以理解为一个Servlet容器
    await  等待
实现类:

    org.apache.catalina.startup.Bootstrap

代码开始(篇幅问题,只说最主要的代码)

Bootstrap的main方法如下:

private static Bootstrap daemon = null;
private Object catalinaDaemon = null;

public static void main(String[] args) {
    //新建一个Bootstrap
    if(daemon == null) {
        Bootstrap t = new Bootstrap();

        try {
            //初始化了ClassLoader,并用ClassLoader创建了Catalina实例,并赋值给catalinaDaemon变量
            t.init();
        } catch (Throwable var3) {
            handleThrowable(var3);
            var3.printStackTrace();
            return;
        }

        daemon = t;
    } else {
        Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
    }

    try {
        String t2 = "start";
        if(args.length > 0) {
            t2 = args[args.length - 1];
        }

        if(t2.equals("startd")) {
            args[args.length - 1] = "start";
            daemon.load(args);
            daemon.start();
        } else if(t2.equals("stopd")) {
            args[args.length - 1] = "stop";
            daemon.stop();
        } else if(t2.equals("start")) {
            daemon.setAwait(true);
            daemon.load(args);
            daemon.start();
        } else if(t2.equals("stop")) {
            daemon.stopServer(args);
        } else if(t2.equals("configtest")) {
            daemon.load(args);
            if(null == daemon.getServer()) {
                System.exit(1);
            }

            System.exit(0);
        } else {
            log.warn("Bootstrap: command \"" + t2 + "\" does not exist.");
        }
    } catch (Throwable var4) {
        Throwable t1 = var4;
        if(var4 instanceof InvocationTargetException && var4.getCause() != null) {
            t1 = var4.getCause();
        }

        handleThrowable(t1);
        t1.printStackTrace();
        System.exit(1);
    }

}
main方法包含俩部分内容:
    1、新建Bootstrap,并执行init方法
    2、处理main方法中传入的命令,如果args参数为空,则默认执行start方法

新建Bootstrap后会执行init方法,也就是上面代码中的init方法:

public void init() throws Exception {
    初始化了ClassLoader
    this.initClassLoaders();
    Thread.currentThread().setContextClassLoader(this.catalinaLoader);
    SecurityClassLoad.securityClassLoad(this.catalinaLoader);
    if(log.isDebugEnabled()) {
        log.debug("Loading startup class");
    }

    Class startupClass = this.catalinaLoader.loadClass("org.apache.catalina.startup.Catalina");
    并用ClassLoader创建了Catalina实例
    Object startupInstance = startupClass.newInstance();
    if(log.isDebugEnabled()) {
        log.debug("Setting startup class properties");
    }

    String methodName = "setParentClassLoader";
    Class[] paramTypes = new Class[]{Class.forName("java.lang.ClassLoader")};
    Object[] paramValues = new Object[]{this.sharedLoader};
    Method method = startupInstance.getClass().getMethod(methodName, paramTypes);
    method.invoke(startupInstance, paramValues);
    并赋值给catalinaDaemon变量
    this.catalinaDaemon = startupInstance;
}

这个方法主要做了三件事:
    1、初始化了ClassLoader
    2、用ClassLoader创建了Catalina实例,并赋值给catalinaDaemon变量
    3、使用catalinaDaemon来执行命令操作

该main方法当为空参时,也就是默认执行start命令:

它执行了下面三个方法:这个三个方法内部都调用了Catalina的相关方法进行具体执行,而且都是用反射来执行的。
  

  daemon.setAwait(true);
  daemon.load(args);
  daemon.start();
以start方法为例:

public void start() throws Exception {
    if(this.catalinaDaemon == null) {
        this.init();
    }

    Method method = this.catalinaDaemon.getClass().getMethod("start", (Class[])null);
    method.invoke(this.catalinaDaemon, (Object[])null);
}
做了三件事:
    1、判断catalinaDaemon是否初始化,如果没有则对其初始化
    2、使用Method进行反射调用它的空参start方法(涉及反射相关知识点内容后期会进行补充)
    3、反射后的调用效果就是:((Catalina)catalinaDaemon).start()
而daemon.setAwait(true)与daemon.load(args)这俩个方法也是用类似的方法调用了Catalina中的setAwait和load方法
下一篇学习Catalina的启动过程

猜你喜欢

转载自blog.csdn.net/fan510988896/article/details/73603306