Tomcat的顶层结构及启动过程

来源:互联网 发布:导航网源码 搜索引擎 编辑:程序博客网 时间:2024/06/05 14:32

写在前面:

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

最近看的这本书里面有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的启动过程

原创粉丝点击