阿里云-云小站(无限量代金券发放中)
【腾讯云】云服务器、云数据库、COS、CDN、短信等热卖云产品特惠抢购

Tomcat源码分析

141次阅读
没有评论

共计 9501 个字符,预计需要花费 24 分钟才能阅读完成。

    Tomcat 有多个容器组成,而 Container 也就是容器与 Connecter 连接器是 Tomcat 最核心的两个模块,Connecter 连接器接收客户端的请求,并根据客户端的请求传递给 Container 处理并作出相应。

Tomcat 中有多个层次的容器对象:Engine、Host、Context、Wrapper,这些容器是有层级关系的。

  • Engine:代表整个 Tomcat 的 Servlet 引擎,可以包含一个或多个子容器
  • Host:表示一个虚拟主机,包含多个 Context
  • Context:表示一个 ServletContext,包含一个或多个 Wrappers 容器
  • Wrappers:表示一个独立的 Servlet 定义,可以是多个 servlet 或一个 servlet 实例

     所有的容器都继承 ContainerBase 抽象类,ContainerBase 抽象类实现 Container 接口,Container 继承 Lifecycle 接口用于实现对容器的生命周期的统一管理。

Container 接口定义了静态字段来表示添加或移除子容器时的事件类型(如下图):

                           Tomcat 源码分析

通过下面图片我们看下 ContainerBase 的类结构,由于篇幅有限方法过多这里就不列出接口、类的字段与方法了:

                         Tomcat 源码分析

                                               ContainerBase 类图

   1、Lifecycle 接口:就是我们前面介绍过的用于控制 Tomcat 所有组件生命周期的接口定义。
   2、LifecycleBase 抽象类:实现了 Lifecycle 接口用户 Tomcat 所有组件生命周期的管理类。
   3、MBeanRegistration 接口:用于使 Tomcat 支持 JMX 而定义的接口。
   4、LifecycleMBeanBase 抽象类:继承了 LifecycleBase 与实现了 MBeanRegistration 接口,实现了 JMX 的支持。
   5、Container 接口:就是我们所有容器的接口,定义了容器通用的字段还有方法。
   6、ContainerBase 抽象类:所有容器的基类,实现了一些子容器管理的方法(添加、移除、查找),子容器的启动、实现了容器事件监听对象的管理、包括对 Loader、Logger、Manager、Realm、Resources 组件的管理、还包括了 Pipeline、Valve 对象的管理等。

  Tomcat 所有容器类图如下(省略了字段、方法):

 Tomcat 源码分析

                                              容器类图

 

这节就先分析到这里,下面我们在详细分析 Tomcat 中的每个容器。

更多 Tomcat 相关教程见以下内容

CentOS 6.6 下安装配置 Tomcat 环境  http://www.linuxidc.com/Linux/2015-08/122234.htm

RedHat Linux 5.5 安装 JDK+Tomcat 并部署 Java 项目  http://www.linuxidc.com/Linux/2015-02/113528.htm 

Tomcat 权威指南(第二版)(中英高清 PDF 版 + 带书签)  http://www.linuxidc.com/Linux/2015-02/113062.htm 

Tomcat 安全配置与性能优化 http://www.linuxidc.com/Linux/2015-02/113060.htm 

Linux 下使用 Xshell 查看 Tomcat 实时日志中文乱码解决方案 http://www.linuxidc.com/Linux/2015-01/112395.htm 

CentOS 64-bit 下安装 JDK 和 Tomcat 并设置 Tomcat 开机启动操作步骤 http://www.linuxidc.com/Linux/2015-01/111485.htm 

CentOS 6.5 下安装 Tomcat  http://www.linuxidc.com/Linux/2015-01/111415.htm 

更多详情见请继续阅读下一页的精彩内容:http://www.linuxidc.com/Linux/2016-03/129505p2.htm

    Tomcat 由多个组件组成,那么 Tomcat 是怎么对他们的生命周期进行管理的么,这里将从 Tomcat 源码去分析其生命周期的实现;

Bootstrape 类为 Tomcat 的入口,所有的组件够通过实现 Lifecycle 接口来管理生命周期,Tomcat 启动的时候只需调用 Server 容器的 start(),然后父容器依序启动他所包含的子容器,关闭也是如此。

     通过阅读源码可知一个 Server 里包含一个或多个 Service,一个 Service 里包含一个 Container,一个或多个 Connector、Container 又包含了 Engine、Host、Context、Wrapper 四个容器;

Tomcat 的组件启动顺序为:

StandardServer.start()——》StandardServer.startInternal() ——》StandardService().start()——StandardService.startInternal() ——>》StandardEngine().start() ——》StandardEngine.startInternal()—》StandardEngine 中启动其他组件,组件关闭也是如此;

 

现在我们通过 Demo 简单模拟 Tomcat 的启动

 

 Tomcat 源码分析

                                                                        模拟 Demo UML 类图

 Tomcat 源码分析

 

                                                                    模拟 Demo 时序图

 

主要代码段如下:

Catalina 类:

package co.solinx.Pattern.Observer;

/**
 * Created by LX on 2014/11/26.
 */
public class Catalina {public static void main(String[] args) {

        //Tomcat 为多个组件组成的 server 为最外围最大的一个
        StandardServer server = new StandardServer();
// 为 server 添加监听器 server.addLifecycleListener(new ContextConfig()); // 添加一个 service StandardService service = new StandardService(); server.AddService(service);
// 为 service 添加监听器 service.addLifecycleListener(new ContextConfig()); // 添加一个 engine StandardEngine standardEngine = new StandardEngine();
// 为 engine 添加监听器 standardEngine.addLifecycleListener(new EngineConfig()); StandardHost standardHost = new StandardHost("localhost"); // StandardHost testHost = new StandardHost("test"); // standardHost.addLifecycleListener(new EngineConfig()); standardEngine.addChild("localhost", standardHost); // standardEngine.addChild("test", testHost); // 往 service 添加 engine 容器 service.setContainer(standardEngine); try {server.start(); } catch (LifecycleException e) {e.printStackTrace(); } } }

StandardServer 类

 

package co.solinx.Pattern.Observer;

/**
 * Created by LX on 2014/11/26.
 */
public class StandardServer extends LifecycleBase implements Context {Service services[] = new Service[0];
    @Override
    protected void startInternal() throws LifecycleException {for (int i = 0; i < services.length; i++) {services[i].start();}

        System.out.println("StandardServer start");
    }
    public void AddService(Service service) {Service result[] = new Service[services.length + 1];
        System.arraycopy(services, 0, result, 0, services.length);
        result[services.length] = service;
        services = result;
    }    
}

StandardService 类:

 

package co.solinx.Pattern.Observer;

/**
 * Created by LX on 2014/11/26.
 */
public class StandardService extends LifecycleBase implements Service, Context {

    protected ContainerBase container = null;

    @Override
    protected void startInternal() throws LifecycleException {container.start();
        System.out.println("StandardService start");
    }

    public void setContainer(ContainerBase container) {this.container = container;}

}

StandardEngine 类:

 

 

package co.solinx.Pattern.Observer;

/**
 * Created by LX on 2014/11/26.
 */
public class StandardEngine extends ContainerBase {
    @Override
    protected void startInternal() throws LifecycleException {super.startInternal();
        System.out.println("StandardEngine start");
    }

    protected void addChild(String key, Container container) {super.addChild(key, container);
    }
}

LifecycleSupport 类:

 

 

package co.solinx.Pattern.Observer;

/**
 * Created by LX on 2014/11/26.
 * 代理了具体监听者
 */
public class LifecycleSupport {public LifecycleSupport(Lifecycle lifecycle) {super();
        this.lifecycle = lifecycle;
    }
    private Lifecycle lifecycle = null;
    private LifecycleListener listeners[] = new LifecycleListener[0];
    private final Object listenersLock = new Object(); // Lock object for changes to listeners
    public void addLifecycleListener(LifecycleListener listener) {synchronized (listenersLock) {LifecycleListener results[] =
                    new LifecycleListener[listeners.length + 1];
            for (int i = 0; i < listeners.length; i++)
                results[i] = listeners[i];
            results[listeners.length] = listener;
            listeners = results;
        }
    }
    public LifecycleListener[] findLifecycleListeners() {return listeners;}
    public void fireLifecycleEvent(String type, Object data) {LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
        LifecycleListener interested[] = listeners;
        for (int i = 0; i < interested.length; i++)
            interested[i].lifecycleEvent(event);
    }
    public void removeLifecycleListener(LifecycleListener listener) {synchronized (listenersLock) {
            int n = -1;
            for (int i = 0; i < listeners.length; i++) {if (listeners[i] == listener) {
                    n = i;
                    break;
                }
            }
            if (n < 0)
                return;
            LifecycleListener results[] =
                    new LifecycleListener[listeners.length - 1];
            int j = 0;
            for (int i = 0; i < listeners.length; i++) {if (i != n)
                    results[j++] = listeners[i];
            }
            listeners = results;
        }
    }
}

 

 

模拟程序运行结果:

 

    Tomcat 有多个容器组成,而 Container 也就是容器与 Connecter 连接器是 Tomcat 最核心的两个模块,Connecter 连接器接收客户端的请求,并根据客户端的请求传递给 Container 处理并作出相应。

Tomcat 中有多个层次的容器对象:Engine、Host、Context、Wrapper,这些容器是有层级关系的。

  • Engine:代表整个 Tomcat 的 Servlet 引擎,可以包含一个或多个子容器
  • Host:表示一个虚拟主机,包含多个 Context
  • Context:表示一个 ServletContext,包含一个或多个 Wrappers 容器
  • Wrappers:表示一个独立的 Servlet 定义,可以是多个 servlet 或一个 servlet 实例

     所有的容器都继承 ContainerBase 抽象类,ContainerBase 抽象类实现 Container 接口,Container 继承 Lifecycle 接口用于实现对容器的生命周期的统一管理。

Container 接口定义了静态字段来表示添加或移除子容器时的事件类型(如下图):

                           Tomcat 源码分析

通过下面图片我们看下 ContainerBase 的类结构,由于篇幅有限方法过多这里就不列出接口、类的字段与方法了:

                         Tomcat 源码分析

                                               ContainerBase 类图

   1、Lifecycle 接口:就是我们前面介绍过的用于控制 Tomcat 所有组件生命周期的接口定义。
   2、LifecycleBase 抽象类:实现了 Lifecycle 接口用户 Tomcat 所有组件生命周期的管理类。
   3、MBeanRegistration 接口:用于使 Tomcat 支持 JMX 而定义的接口。
   4、LifecycleMBeanBase 抽象类:继承了 LifecycleBase 与实现了 MBeanRegistration 接口,实现了 JMX 的支持。
   5、Container 接口:就是我们所有容器的接口,定义了容器通用的字段还有方法。
   6、ContainerBase 抽象类:所有容器的基类,实现了一些子容器管理的方法(添加、移除、查找),子容器的启动、实现了容器事件监听对象的管理、包括对 Loader、Logger、Manager、Realm、Resources 组件的管理、还包括了 Pipeline、Valve 对象的管理等。

  Tomcat 所有容器类图如下(省略了字段、方法):

 Tomcat 源码分析

                                              容器类图

 

这节就先分析到这里,下面我们在详细分析 Tomcat 中的每个容器。

更多 Tomcat 相关教程见以下内容

CentOS 6.6 下安装配置 Tomcat 环境  http://www.linuxidc.com/Linux/2015-08/122234.htm

RedHat Linux 5.5 安装 JDK+Tomcat 并部署 Java 项目  http://www.linuxidc.com/Linux/2015-02/113528.htm 

Tomcat 权威指南(第二版)(中英高清 PDF 版 + 带书签)  http://www.linuxidc.com/Linux/2015-02/113062.htm 

Tomcat 安全配置与性能优化 http://www.linuxidc.com/Linux/2015-02/113060.htm 

Linux 下使用 Xshell 查看 Tomcat 实时日志中文乱码解决方案 http://www.linuxidc.com/Linux/2015-01/112395.htm 

CentOS 64-bit 下安装 JDK 和 Tomcat 并设置 Tomcat 开机启动操作步骤 http://www.linuxidc.com/Linux/2015-01/111485.htm 

CentOS 6.5 下安装 Tomcat  http://www.linuxidc.com/Linux/2015-01/111415.htm 

更多详情见请继续阅读下一页的精彩内容:http://www.linuxidc.com/Linux/2016-03/129505p2.htm

    从 Tomcat 启动调用栈可知,Bootstrap 类的 main 方法为整个 Tomcat 的入口,在 init 初始化 Bootstrap 类的时候为设置 Catalina 的工作路径也就是 Catalina_HOME 信息、Catalina.base 信息,在 initClassLoaders 方法中初始化类加载器,然后通过反射初始化 org.apache.catalina.startup.Catalina 作为 catalina 守护进程;

一、load

Tomcat 源码分析
Bootstrap 中 load 流程:

  1. 反射调用 Catalina 的 load 方法。
  2. 调用 Catalina 的 initDirs()、initNaming()初始化 catalinaHome、catalina.useNaming 等信息。
  3. 创建 Digester 对象,调用 createStartDigester 创建与配置 Digester 信息,载入 Server.xml 配置文件,使用 Digester 解析 Server.xml 文件,并根据 Server 文件的配置信息创建 Server、Service、Engine、Host、Valve、Realm、Connector、Listener、Resource 等对象。
  4. 设置当前 Catalina 为 StandardServer 的 Catalina 对象,调用 initStreams。
  5. 调用 StandardServer 的 init 方法初始化 Server。

    调用 Bootstrap 的 load 方法中用反射调用 Catalina 的 load,在 Catalina 中初始化 initDirs()路径信息,调用 createStartDigester 创建与配置 Digester 信息,载入 Server.xml 配置文件,使用 Digester 解析 Server.xml 文件,并根据 Server 文件的配置信息创建 Server、Service、Engine、Host、Valve、Realm、Connector、Listener、Resource 等对象,及对象的关联关系(Digester 的相关知识这里就不介绍了)。由于在 Digester 解析 Server.xml 的时候已经创建 Server 对象,所以这里也将 server 的 init 方法初始化 Server 对象,至此 Bootstrap 执行完成,准确的说是 Catalina 的 load 载入完成。

二、start
    接着将调用 Bootstrap 的 start 方法启动容器,在 start 方法中也是通过反射调用 Catalina 的 start 方法,如下图:

Tomcat 源码分析

    然后在 Catalina 中调用 StandardServer 对象的 start 方法启动 server,在 start 方法中就会像我们在 Tomcat 源码分析之—组件启动实现分析那节中分析的一样,通过 Tomcat 的生命周期管理观察者模式实现对 Service、Connector、Engine、Host、Context、Wrapper、Pipeline 的启动,这里就不重复在讲解了;

三、注册关闭钩子(ShutdownHook)

1 if (shutdownHook == null) {2     shutdownHook = new CatalinaShutdownHook();
3 }
4 Runtime.getRuntime().addShutdownHook(shutdownHook);

四、调用 await()与 stop(),等候关闭请求与 stop 容器
Tomcat 源码分析
    调用 Catalina 的 await 实际上就调用 StandardServer 的 await 如上图,等候 <Server port=”8006″ shutdown=”SHUTDOWN”> 在 Server 8006 端口上的 SHUTDOWN 关闭 Tomcat 请求。
接收到 SHUTDOWN 请求后调用 StandardServer 的 stop 方法与 destroy 方法如下图:
Tomcat 源码分析
生命周期管理观察者模式实现对 Service、Connector、Engine、Host、Context、Wrapper、Pipeline 的关闭与释放资源

五、总结
    Tomcat 的启动与关闭流程到此就结束了,整个流程还是比较清晰的,只要清除 Tomcat 的启动流程也自然就懂得了 Tomcat 的关闭流程,Tomcat 中使用了观察者模式对 Tomcat 的生命周期进行了管理,了解 LifecycleBase、Lifecycle、LifecycleSupport 等相关类也就了解了整个流程,整个流程的时序图如下:

Tomcat 源码分析

                                                           Tomcat 启动与关闭时序图

Tomcat 的详细介绍:请点这里
Tomcat 的下载地址:请点这里

本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-03/129505.htm

正文完
星哥说事-微信公众号
post-qrcode
 
星锅
版权声明:本站原创文章,由 星锅 2022-01-21发表,共计9501字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
【腾讯云】推广者专属福利,新客户无门槛领取总价值高达2860元代金券,每种代金券限量500张,先到先得。
阿里云-最新活动爆款每日限量供应
评论(没有评论)
验证码
【腾讯云】云服务器、云数据库、COS、CDN、短信等云产品特惠热卖中