• 深入分析理解Tomcat体系结构


    Tomcat整体结构

      由上图可知Tomcat的顶层容器是Server,而且一个Tomcat对应一个Server,一个server有多个service提供服务.service包含两个重要组件:Connector和Container.这个后面详细讲解.这个Server由谁来管理呢?当然是Catalina了,她是tomcat的管理类,她的三个方法load,start,stop分别用来管理整个服务器的生命周期.

    Load方法:Load方法根据conf/server.xml文件创建Server并调用Server的init方法进行初始化.Server的init方法调用所有service的init方法,service的init方法调用所有Connector和Container的init方法.整个初始化工作就完成了.

    Start方法:用于启动服务,类似init,也是逐层进行启动.

    Stop方法:用于关闭服务,类似init,也是逐层调用关闭.

    最后,CatAlina中的await方法非常重要,这个方法调用Server中的await方法,这个方法的作用就是进入一个循环,保持主线程不退出.

    Tomcat组件启动过程

    Bootstrap的启动过程

    Tomcat启动的入口方法就是Bootstrap中的main方法,代码如下:

     public static void main(String args[]) {
            if (daemon == null) {
                // Don't set daemon until init() has completed
                Bootstrap bootstrap = new Bootstrap();
                try {//初始化ClassLoader,创建了Catalina实例,赋值给catalinaDaemon
                    bootstrap.init();
                } catch (Throwable t) {
                    handleThrowable(t);
                    t.printStackTrace();
                    return;
                }
                daemon = bootstrap;
            } else {
                // When running as a service the call to stop will be on a new
                // thread so make sure the correct class loader is used to prevent
                // a range of class not found exceptions.
                Thread.currentThread().setContextClassLoader(daemon.catalinaLoader);
            }
            //根据args参数执行不同的命令
            try {
                String command = "start";//默认执行start
                if (args.length > 0) {
                    command = args[args.length - 1];
                }
                if (command.equals("startd")) {
                    args[args.length - 1] = "start";
                    daemon.load(args);
                    daemon.start();
                } else if (command.equals("stopd")) {
                    args[args.length - 1] = "stop";
                    daemon.stop();
                } else if (command.equals("start")) {
                    daemon.setAwait(true);
                    daemon.load(args);
                    daemon.start();
                } else if (command.equals("stop")) {
                    daemon.stopServer(args);
                } else if (command.equals("configtest")) {
                    daemon.load(args);
                    if (null==daemon.getServer()) {
                        System.exit(1);
                    }
                    System.exit(0);
                } else {
                    log.warn("Bootstrap: command "" + command + "" does not exist.");
                }
            } catch (Throwable t) {
                // Unwrap the Exception for clearer error reporting
                if (t instanceof InvocationTargetException &&
                        t.getCause() != null) {
                    t = t.getCause();
                }
                handleThrowable(t);
                t.printStackTrace();
                System.exit(1);
            }
    }
    View Code
    public void start()
            throws Exception {
            if( catalinaDaemon==null ) init();
    
            Method method = catalinaDaemon.getClass().getMethod("start", (Class [] )null);
            method.invoke(catalinaDaemon, (Object [])null);
    
        }
    View Code

    调用执行start方法前,先判断catalinaDaemon有没有被初始化,如果没有则执行init方法,然后使用Method进行反射调用Catalina的start方法.

    知识点补充:

    Method是java.lang.reflect包里的类,可以使用其中的invoke方法来执行所代表的方法,invoke里有两个参数,第一个参数是Method方法所在的实体,第二个参数是可变参数,用于Method方法执行时所需要的参数.

    Catalina的启动过程

    Catalina的启动主要调用setAwait,load和start方法来完成.setAwait方法用于设置Server启动后是否进入等待状态的标志,为true进入,否则不进入.load方法用于加载配置文件,start方法用于启动服务器.

    public void setAwait(boolean b) {
            await = b;
        }
    
    public void load() { 
            //...创建server
        try {
                getServer().init();
            } catch (LifecycleException e) {
                if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
                    throw new java.lang.Error(e);
                } else {
                    log.error("Catalina.start", e);
                }
    
            }
            //...
        }
    
        /**
         * Start a new server instance.
         */
        public void start() {
    
            if (getServer() == null) {
                load();
            }
    
            if (getServer() == null) {
                log.fatal("Cannot start server. Server instance is not configured.");
                return;
            }
    
            long t1 = System.nanoTime();
    
            // Start the new server
            try {
                getServer().start();
            } catch (LifecycleException e) {
                log.fatal(sm.getString("catalina.serverStartFail"), e);
                try {
                    getServer().destroy();
                } catch (LifecycleException e1) {
                    log.debug("destroy() failed for failed Server ", e1);
                }
                return;
            }
            //...
            if (await) {
                await();
                stop();
            }
        }
    View Code

    Server的启动过程

      Server接口中提供了addService(Service service),removeService(Service service)来增加和删除Service,Server中的init和start方法循环调用Service中的init和start方法来启动所有Service.Server的默认实现是StandardServer.

    Service的启动过程

      Service的默认实现是StandardService,和StandardServer一样也继承自LifecycleMBeanBase类,所以init和start方法最终会调用initInternal和startInternal方法.而StandardService中的initInternal和startInternal方法主要调用container,executors,mapperListener,connectors的init和start方法.

    Tomcat声明周期管理

    1.Lifecycle接口

      Tomcat通过Lifecycle接口统一管理生命周期,所有生命周期组件都要实现这个接口,Lifecycle接口主要做了4件事:

    1)       定义了13个String类型常量,用于LifecycleEvent事件的type属性中,作用是为了区分组件发出LifecycleEvent事件的状态.

    2)       定义了3个管理监听器的方法addLifecycleListener,findLifecycleListener,removeLifecycleListener,分别用来添加,查找,删除LifecycleListener类型的监听器.

    3)       定义了4个生命周期方法:init,start,stop和destroy,用于执行生命周期的各个阶段的操作.

    4)       定义了获取当前状态的两个方法:getState和getStateName,用来获取当前的状态.

    具体接口代码如下:

    public interface Lifecycle {
        //13中LifecycleEvent事件的类型
        public static final String BEFORE_INIT_EVENT = "before_init";
    
        public static final String AFTER_INIT_EVENT = "after_init";
    
        public static final String START_EVENT = "start";
    
        public static final String BEFORE_START_EVENT = "before_start";
    
        public static final String AFTER_START_EVENT = "after_start";
    
        public static final String STOP_EVENT = "stop";
    
        public static final String BEFORE_STOP_EVENT = "before_stop";
    
        public static final String AFTER_STOP_EVENT = "after_stop";
    
        public static final String AFTER_DESTROY_EVENT = "after_destroy";
    
        public static final String BEFORE_DESTROY_EVENT = "before_destroy";
    
        public static final String PERIODIC_EVENT = "periodic";
    
        public static final String CONFIGURE_START_EVENT = "configure_start";
    
        public static final String CONFIGURE_STOP_EVENT = "configure_stop";
    
        //3个管理监听器的方法
        public void addLifecycleListener(LifecycleListener listener);
    
        public LifecycleListener[] findLifecycleListeners();
    
        public void removeLifecycleListener(LifecycleListener listener);
    
        //4个生命周期方法
        public void init() throws LifecycleException;
    
        public void start() throws LifecycleException;
    
        public void stop() throws LifecycleException;
    
        public void destroy() throws LifecycleException;
    
        //2个获取当前状态的方法
        public LifecycleState getState();
    
        public String getStateName();
    }
    View Code

    2.LifecycleBase

      LifecycleBase是Lifecycle的默认实现,所有实现了生命周期的组件都直接或间接的继承了LifecycleBase.LifecycleBase为Lifecycle里的接口方法提供了默认实现.监听器管理是专门提供了一个LifecycleSupport类来完成,在LifecycleSupport中定义了LifecycleListener类型的数组,用来保存所有监听器,并定义了添加,删除,查找,执行监听器的方法;生命周期中设置了相应的状态并调用了相应的模板方法,init,start,stop,destroy所对应的模板方法分别是initInternal,startInternal,stopInternal,destroyInternal方法,执行生命周期就是这4个方法.组件的当前状态在这4个方法中已经设置好了,所以直接返回就OK了.

    Container分析

      Container是Tomcat中容器的接口,通常使用的Servlet就封装在其子接口Wrapper中.Container一共有4个接口Engine,Host,Context,Wrapper和一个默认实现类ContainerBase,每个子接口都是一个容器,这四个容器都有一个对应的StandardXXX实现类,并且这些实现类都继承自ContainerBase类.Container还继承Lifecycle接口,而且ContainerBase间接继承LifecycleBase. 4个接口Engine,Host,Context,Wrapper也符合Tomcat的生命周期管理模式.

    1.Container容器结构

    2.4个容器的作用

    Engine:引擎,用来管理多个站点,一个Service最多只能有一个Engine.

    Host:代表一个站点,也可叫虚拟主机,通过配置Host来添加站点.

    Context:代表一个应用程序,对应一套程序或者WEB-INF目录及下面的web.xml

    Wraper:每个Wrapper封装着一个Servlet.

    Pipeline-value管道

      Container处理请求是使用Pipeline-value管道来处理的.Pipeline-value是责任链模式,区别于普通的责任链模式:

    1)       每个Pipeline都有特定的Value,而且是在管道的最后执行,这个value叫做BaseValue,是不可删除的.

    2)       在上层容器的BaseValue中会调用下层容器的管道.

    Pipeline的实现方法

             Pipeline管道的实现分为生命周期管理和处理请求两部分.

    1.生命周期实现方法

             Container中的Pipeline在抽象实现类ContainerBase中定义,并在生命周期的startInternal,stopInternal,destroyInternal方法中调用管道的相应生命周期方法.

    2.处理请求实现方法

             Pipeline调用所包含Value的invoke方法来处理请求,并且在BaseValue里又调用了子容器Pipeline所包含Value的invoke方法,直到最后调用了Wrapper的Pipeline所包含的BaseValue—StandardWrapperValue

    Connector分析

      Connector用于接收请求并将请求封装成Request和Response来具体处理,最底层是使用Socket来进行连接的,Request和Response是按照Http协议来封装的,所以Connector同时实现了TCP/IP协议和HTTP协议,Request和Response封装完之后交给Container进行处理,Container就是Servlet容器,Container处理完成之后返回给Connector,最后Connector使用Socket将处理结果返回给客户端,整个请求就完成了.

      Connector中具体是用ProtocolHandler来处理请求,并且Connector的创建过程主要是初始化ProtocolHandler.不同的ProtocolHandler代表不同的连接类型.Http11Protocol使用的是普通的Socket来连接的.Http11NioProtocol使用的是NioSocket来连接的.

    Protocol三个重要组件:

    Endpoint:用于处理底层的Socket网络连接.

    Processor:用于将Enpoint接收到的请求封装成Request

    Adapter:用于将封装好的Request交给Container处理.

    最近学习有些懈怠了,主要是工作太忙,下班后基本剩下上床睡觉了.无论如何还是要不断加强学习,提高自身技术水平.

  • 相关阅读:
    常用函数集锦
    HDU1212加深下对取模运算的理解
    HDU1022 queue和vector模拟
    设计模式原则
    3.6html学习笔记之样式选择
    poj 1274(二分图最大匹配)
    poj 1469(二分图最大匹配)
    poj 3692(二分图匹配--最大独立集)
    Codeforces Round #230 (Div. 1) 解题报告
    Codeforces Rockethon 2014 解题报告
  • 原文地址:https://www.cnblogs.com/fxust/p/8007273.html
Copyright © 2020-2023  润新知