zoukankan      html  css  js  c++  java
  • How Tomcat Works(十七)

    在前面的文章中,已经学会了如何通过实例化一个连接器和容器来获得一个servlet容器,并将连接器和容器相关联;但在前面的文章中只有一个连接器可用,该连接器服务8080端口上的HTTP请求,无法添加另一个连接器来服务诸如HTTPS之类的其他请求;此外,在前面的文章中的应用程序中有些缺憾,即缺少一种启动/关闭servlet容器的机制。

    org.apache.catalina.Server接口的实例表示Catalina的整个servlet引擎,囊括了所有的组件;它使用一个优雅的方式来启动/关闭整个系统,不需要再对连接器和容器分别启动/关闭(当启动Server组件时,它会启动其中所有的组件,然后它就无限期地等待关闭命令;如果想要关闭系统,可以向指定端口发送一条关闭命令,Server组件接收到关闭命令后,就会关闭其中所有的组件)。

    Server组件使用了另一个组件(即Service组件)来包含其他组件,如一个容器组件和一个或多个连接器组件。

    下面是Server接口的定义

    public interface Server {
       
        public String getInfo();
        
        public NamingResources getGlobalNamingResources();
       
        public void setGlobalNamingResources(NamingResources globalNamingResources);
       
        public int getPort();
       
        public void setPort(int port);
        
        public String getShutdown();
       
        public void setShutdown(String shutdown);
       
        public void addService(Service service);
        
        public void await();
        
        public Service findService(String name);
        
        public Service[] findServices();
       
        public void removeService(Service service);
       
        public void initialize()   throws LifecycleException;
    }

    shutdown属性保存了必须发送给Server实例用来关闭整个系统的关闭命令,port属性定义了Server组件会从哪个端口获取关闭命令,可以调用addService()方法为Server组件添加Service组件,或通过removeService()方法删除某个Service组件,findService()方法将会返回添加到该Server组件中的所有Service组件,initialize()方法包含在系统启动前要执行的一些代码

     org.apache.catalina.core.StandardServer类是Server接口的标准实现,介绍这个类是因为我们对其中的关闭机制比较感兴趣,而这也是这个类中最重要的特性;该类的许多方法都与新server.xml文件中的服务器配置的存储相关,但这并不是本文的重点。

    一个Server组件可以有多个Service组件,StandardServer类提供了addService()方法、 removeService()方法和findServices()方法的实现

    StandardServer类有四个与生命周期相关的方法,分别是initialize()方法、 start()方法、 stop()方法和await()方法,就像其他组件一样,可以初始化并启动Server组件,然后调用await()方法及stop()方法。调用await()方法后会一直阻塞住,直到它总8085端口上接收到关闭命令。当await()方法返回时,会运行stop()方法来关闭其下的所有子组件。

    Server实例的initialize()方法用于初始化添加到其中的Service组件,下面是tomcat4中StandardServer类中initialize()方法的实现

    public void initialize()    throws LifecycleException {
            if (initialized)
                throw new LifecycleException (
                    sm.getString("standardServer.initialize.initialized"));
            initialized = true;
    
            // Initialize our defined Services
            for (int i = 0; i < services.length; i++) {
                services[i].initialize();
            }
        }

    start()方法用于启动Server组件,在StandardServer类的start()方法的实现中,它会启动其所有的Service组件,这些Service组件它们逐个启动所有其他的组件,如连接器组件和servlet容器。

    public void start() throws LifecycleException {
    
            // Validate and update our current component state
            if (started)
                throw new LifecycleException
                    (sm.getString("standardServer.start.started"));
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
    
            lifecycle.fireLifecycleEvent(START_EVENT, null);
            started = true;
    
            // Start our defined Services
            synchronized (services) {
                for (int i = 0; i < services.length; i++) {
                    if (services[i] instanceof Lifecycle)
                        ((Lifecycle) services[i]).start();
                }
            }
    
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
    
        }

    stop()方法用于关闭Server组件

    public void stop() throws LifecycleException {
    
            // Validate and update our current component state
            if (!started)
                throw new LifecycleException
                    (sm.getString("standardServer.stop.notStarted"));
    
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
    
            lifecycle.fireLifecycleEvent(STOP_EVENT, null);
            started = false;
    
            // Stop our defined Services
            for (int i = 0; i < services.length; i++) {
                if (services[i] instanceof Lifecycle)
                    ((Lifecycle) services[i]).stop();
            }
    
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
    
        }

    await()方法负责停止整个tomcat部署的机制

    /**
         * Wait until a proper shutdown command is received, then return.
         */
        public void await() {
    
            // Set up a server socket to wait on
            ServerSocket serverSocket = null;
            try {
                serverSocket =
                    new ServerSocket(port, 1,
                                     InetAddress.getByName("127.0.0.1"));
            } catch (IOException e) {
                System.err.println("StandardServer.await: create[" + port
                                   + "]: " + e);
                e.printStackTrace();
                System.exit(1);
            }
    
            // Loop waiting for a connection and a valid command
            while (true) {
    
                // Wait for the next connection
                Socket socket = null;
                InputStream stream = null;
                try {
                    socket = serverSocket.accept();
                    socket.setSoTimeout(10 * 1000);  // Ten seconds
                    stream = socket.getInputStream();
                } catch (AccessControlException ace) {
                    System.err.println("StandardServer.accept security exception: "
                                       + ace.getMessage());
                    continue;
                } catch (IOException e) {
                    System.err.println("StandardServer.await: accept: " + e);
                    e.printStackTrace();
                    System.exit(1);
                }
    
                // Read a set of characters from the socket
                StringBuffer command = new StringBuffer();
                int expected = 1024; // Cut off to avoid DoS attack
                while (expected < shutdown.length()) {
                    if (random == null)
                        random = new Random(System.currentTimeMillis());
                    expected += (random.nextInt() % 1024);
                }
                while (expected > 0) {
                    int ch = -1;
                    try {
                        ch = stream.read();
                    } catch (IOException e) {
                        System.err.println("StandardServer.await: read: " + e);
                        e.printStackTrace();
                        ch = -1;
                    }
                    if (ch < 32)  // Control character or EOF terminates loop
                        break;
                    command.append((char) ch);
                    expected--;
                }
    
                // Close the socket now that we are done with it
                try {
                    socket.close();
                } catch (IOException e) {
                    ;
                }
    
                // Match against our command string
                boolean match = command.toString().equals(shutdown);
                if (match) {
                    break;
                } else
                    System.err.println("StandardServer.await: Invalid command '" +
                                       command.toString() + "' received");
    
            }
    
            // Close the server socket and return
            try {
                serverSocket.close();
            } catch (IOException e) {
                ;
            }
    
        }

    await()方法创建一个ServerSocket对象,监听8085端口,并在while循环中调用它的accept()方法,挡在指定端口上接收到消息时,才会从accept()方法中返回,然后将接收到的消息与关闭命令的字符串相比较,相同的话就跳出while循环,关闭ServerSocket,否则会再次循环,继续等待消息。

    Service组件是org.apache.catalina.Service接口的实例,一个Service组件可以有一个servlet容器和多个连接器实例,可以自由地把连接器实例添加到Service组件中,所有的连接器都会与该servlet容器相关联

    下面是Service接口的定义

    public interface Service {
       
        public Container getContainer();
      
        public void setContainer(Container container);
       
        public String getInfo();
       
        public String getName();
        
        public void setName(String name);
       
        public Server getServer();
       
        public void setServer(Server server);    
       
        public void addConnector(Connector connector);
       
        public Connector[] findConnectors();
       
        public void removeConnector(Connector connector);
       
        public void initialize()   throws LifecycleException;
    }

    org.apache.catalina.core.StandardService类是Service接口的标准实现,StandardService类的initialize()方法用于初始化添加到其中的所有连接器;此外,还实现了org.apache.catalina.Lifecycle接口,它的start()方法用于启动servlet容器和所有连接器

    StandardService实例中有两种组件,分别是连接器和servlet容器,其中servlet容器只有一个,而连接器则可以有多个,多个连接器使tomcat可以为多种不同的请求协议提供服务。例如,一个连接器处理HTTP请求,而另一个可以处理HTTPS请求。

    StandardService类使用变量container来指向一个Container接口的实例,使用数组connectors来保存所有连接器的引用

    private Container container = null;

    private Connector connectors[] = new Connector[0];

    需要调用setContainer()方法将servlet容器与Service组件相关联:

    public void setContainer(Container container) {
    
            Container oldContainer = this.container;
            if ((oldContainer != null) && (oldContainer instanceof Engine))
                ((Engine) oldContainer).setService(null);
            this.container = container;
            if ((this.container != null) && (this.container instanceof Engine))
                ((Engine) this.container).setService(this);
            if (started && (this.container != null) &&
                (this.container instanceof Lifecycle)) {
                try {
                    ((Lifecycle) this.container).start();
                } catch (LifecycleException e) {
                    ;
                }
            }
            synchronized (connectors) {
                for (int i = 0; i < connectors.length; i++)
                    connectors[i].setContainer(this.container);
            }
            if (started && (oldContainer != null) &&
                (oldContainer instanceof Lifecycle)) {
                try {
                    ((Lifecycle) oldContainer).stop();
                } catch (LifecycleException e) {
                    ;
                }
            }
    
            // Report this property change to interested listeners
            support.firePropertyChange("container", oldContainer, this.container);
    
        }

    与Service组件相关联的servlet容器的实例将被传给每个连接器对象的setContainer()方法,这样在Service组件中就可以形成每个连接器和servlet容器之间的关联关系。

    可以调用addConnector()方法将连接器添加到Service组件中,调用removeConnector()方法将某个连接器移除

     public void addConnector(Connector connector) {
    
            synchronized (connectors) {
                connector.setContainer(this.container);
                connector.setService(this);
                Connector results[] = new Connector[connectors.length + 1];
                System.arraycopy(connectors, 0, results, 0, connectors.length);
                results[connectors.length] = connector;
                connectors = results;
    
                if (initialized) {
                    try {
                        connector.initialize();
                    } catch (LifecycleException e) {
                        e.printStackTrace(System.err);
                    }
                }
    
                if (started && (connector instanceof Lifecycle)) {
                    try {
                        ((Lifecycle) connector).start();
                    } catch (LifecycleException e) {
                        ;
                    }
                }
    
                // Report this property change to interested listeners
                support.firePropertyChange("connector", null, connector);
            }
    
        }

    在上面方法中,会初始化并启动添加到其中的连接器。

    public void removeConnector(Connector connector) {
    
            synchronized (connectors) {
                int j = -1;
                for (int i = 0; i < connectors.length; i++) {
                    if (connector == connectors[i]) {
                        j = i;
                        break;
                    }
                }
                if (j < 0)
                    return;
                if (started && (connectors[j] instanceof Lifecycle)) {
                    try {
                        ((Lifecycle) connectors[j]).stop();
                    } catch (LifecycleException e) {
                        ;
                    }
                }
                connectors[j].setContainer(null);
                connector.setService(null);
                int k = 0;
                Connector results[] = new Connector[connectors.length - 1];
                for (int i = 0; i < connectors.length; i++) {
                    if (i != j)
                        results[k++] = connectors[i];
                }
                connectors = results;
    
                // Report this property change to interested listeners
                support.firePropertyChange("connector", connector, null);
            }
    
        }

    与生命周期相关的方法包括从Lifecycle接口中实现的start()方法和stop()方法,在加上initialize()方法,其中initialize()方法会调用该Service组件中所有连接器的上initialize()方法:

    public void initialize()  throws LifecycleException {
            if (initialized)
                throw new LifecycleException (
                    sm.getString("standardService.initialize.initialized"));
            initialized = true;
    
            // Initialize our defined Connectors
            synchronized (connectors) {
                    for (int i = 0; i < connectors.length; i++) {
                        connectors[i].initialize();
                    }
            }
        }

    start()方法负责启动被添加到该Service组件中的连接器和servlet容器:

    public void start() throws LifecycleException {
    
            // Validate and update our current component state
            if (started) {
                throw new LifecycleException
                    (sm.getString("standardService.start.started"));
            }
    
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(BEFORE_START_EVENT, null);
    
            System.out.println
                (sm.getString("standardService.start.name", this.name));
            lifecycle.fireLifecycleEvent(START_EVENT, null);
            started = true;
    
            // Start our defined Container first
            if (container != null) {
                synchronized (container) {
                    if (container instanceof Lifecycle) {
                        ((Lifecycle) container).start();
                    }
                }
            }
    
            // Start our defined Connectors second
            synchronized (connectors) {
                for (int i = 0; i < connectors.length; i++) {
                    if (connectors[i] instanceof Lifecycle)
                        ((Lifecycle) connectors[i]).start();
                }
            }
    
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
    
        }

    stop()方法用于关闭与该Service组件相关联的servlet容器和所有连接器

    public void stop() throws LifecycleException {
    
            // Validate and update our current component state
            if (!started) {
                throw new LifecycleException
                    (sm.getString("standardService.stop.notStarted"));
            }
    
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(BEFORE_STOP_EVENT, null);
    
            lifecycle.fireLifecycleEvent(STOP_EVENT, null);
    
            System.out.println
                (sm.getString("standardService.stop.name", this.name));
            started = false;
    
            // Stop our defined Connectors first
            synchronized (connectors) {
                for (int i = 0; i < connectors.length; i++) {
                    if (connectors[i] instanceof Lifecycle)
                        ((Lifecycle) connectors[i]).stop();
                }
            }
    
            // Stop our defined Container second
            if (container != null) {
                synchronized (container) {
                    if (container instanceof Lifecycle) {
                        ((Lifecycle) container).stop();
                    }
                }
            }
    
            // Notify our interested LifecycleListeners
            lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
    
        }

    在前面文章的应用程序中,通过按某个键或强制中断的方式关闭servlet容器,Stopper类提供了一种更优雅的方式来关闭Catalina服务器;此外,它也保证了所有的生命周期组件的stop()方法都能够调用。

    public class Stopper {
    
      public static void main(String[] args) {
        // the following code is taken from the Stop method of
        // the org.apache.catalina.startup.Catalina class
        int port = 8005;
        try {
          Socket socket = new Socket("127.0.0.1", port);
          OutputStream stream = socket.getOutputStream();
          String shutdown = "SHUTDOWN";
          for (int i = 0; i < shutdown.length(); i++)
            stream.write(shutdown.charAt(i));
          stream.flush();
          stream.close();
          socket.close();
          System.out.println("The server was successfully shut down.");
        }
        catch (IOException e) {
          System.out.println("Error. The server has not been started.");
        }
      }
    }

    --------------------------------------------------------------------------- 

    本系列How Tomcat Works系本人原创 

    转载请注明出处 博客园 刺猬的温驯 

    本人邮箱: chenying998179#163.com (#改为@

    本文链接http://www.cnblogs.com/chenying99/p/3249158.html

  • 相关阅读:
    JAVA -数据类型与表达式---表达式
    JAVA -数据类型与表达式---基本数据类型
    【网易官方】极客战记(codecombat)攻略-森林-背靠背-back-to-back
    【网易官方】极客战记(codecombat)攻略-森林-荆棘农场thornbush-farm
    【网易官方】极客战记(codecombat)攻略-森林-村庄守护者
    【网易官方】极客战记(codecombat)攻略-森林-If 的盛宴
    【网易官方】极客战记(codecombat)攻略-森林-鹰眼
    【网易官方】极客战记(codecombat)攻略-森林-野餐毁灭者
    【网易官方】极客战记(codecombat)攻略-森林-巡逻兵克星A
    【网易官方】极客战记(codecombat)攻略-森林-巡逻兵克星
  • 原文地址:https://www.cnblogs.com/chenying99/p/3249158.html
Copyright © 2011-2022 走看看