How Tomcat Works學習筆記

 

Server和Service

         在前面的章節中Catalina已經有了連接器(Connector)和容器(Container),但是還缺少一種好的啓動和停止Servlet容器的機制,Server和Service能很好的解決這個問題。

Server

         org.apache.catalina.Server接口表示完整的Servlet容器和相關的其他組件,提供了優雅啓動和停止整個系統的機制,有了它以後沒有必要再分別去啓動連接器和容器。

         當你啓動一個Server的時候,它會啓動在其內的所有組件,然後等待識別的shutdown命令,一旦通過指定的端口發送了shutdown命令,被server接收到以後它將停止所有的組件,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;

}

通過addService方法可以下Server添加Service對象。

StandardServer

    StandardServer是Server接口的標準實現,其中最重要的是他的shutdown機制,同時也包括一些解析Server配置(server.xml)的方法。

    一個Server包括一個或多個Service,提供了addService和removeService方法,作爲組件,Server也實現了生命週期的相關功能,提供了initialize、start、stop和await方法。

initialize方法

         initialize方法會初始化Service並添加到Server實例當中:

         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();

        }

}

在StandardServer中增加了initialized變量,防止重複初始化Server。

start方法

         start方法會啓動所有的Service,從而啓動其它組件,像連接器、容器等:

         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);

}

在StandardServer中添加了started變量控制重複調用start方法。

stop方法

         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);

    }

         stop方法會停止所有service,並把started改爲false,從而可以再次啓動Server。

await方法

         await方法的職責是停止整個Tomcat部署:

         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方法會監聽來自客戶端的命令,一旦發現傳來shutdown的命令,將會停止這個Tomcat部署。

Service

         org.apache.catalina.Service接口表示一個服務,一個服務可以包括一個容器和多個連接器,所有的連接器都必須分配給容器,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;

}

StandardService

         StandardService是Service的標準實現類,包括兩種類型的組件:連接器和容器

         通過setContainer方法爲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);

}

通過addConnector方法添加連接器:

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);

        }

 }

    通過removeConnector方法移除連接器:

    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);

        }

}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章