tomcat(14)服务器组件和服务组件

【0】README

0.1)本文部分文字描述转自 “how tomcat works”,旨在学习 “tomcat(14)服务器组件和服务组件” 的基础知识;

0.2)for complete source code ,please visit  https://github.com/pacosonTang/HowTomcatWorks/tree/master/chapter14

【1】服务器组件(org.apache.catalina.Server)

1)org.apache.catalina.Server接口的实例表示 Catalina的整个servlet引擎,囊括了所有的组件。服务器组件使用了一种优雅的方法来启动/关闭 整个系统,不需要再对连接器和容器分别启动/ 关闭;

2)启动/关闭机制的工作原理:当启动服务器组件时,它会启动其中所有的组件,然后它就无限期地等待关闭命令。如果想要关闭系统,可以向指定端口发送一条关闭命令。服务器组件接收到关闭命令后,就会关闭其中所有的组件;

3)服务组件:服务器组件引入了服务组件来包含其他组件,如一个容器组件和一个或多个连接器组件;(干货——注意区分服务器组件和服务组件,以下代码摘自某测试用例,StandardService表服务组件,而StandardServer表服务器组件)

Service service = new StandardService();
    service.setName("Stand-alone Service");
    Server server = new StandardServer();
    server.addService(service);

4)服务器组件Server接口定义

package org.apache.catalina;
import org.apache.catalina.deploy.NamingResources;
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;
}

对以上代码的分析(Analysis):

A1)shutdown属性:保存了必须发送给Server 实例用来关闭整个系统的关闭命令;

A2)port属性:定义了服务器组件会从哪个端口获取关闭命令;

A3)addService() 和 removeService()方法:为服务器组件添加或移除服务组件;

A4)findService()方法:返回添加到该服务器组件中的所有服务组件;

A5)initialize()方法:包含在系统启动前要执行的一些代码;

【2】StandardServer类

1)intro:一个服务器组件可以有0个或多个服务组件;(干货——一个服务器组件可以有0个或多个服务组件)

2)StandardServer类有4个与生命周期相关的方法,分别是initialize()方法,start()方法,stop()方法 和 await()方法;

【2.1】initialize()方法

1)intro:用于初始化添加到其中的服务器组件;

 public void initialize()  throws LifecycleException {  //org.apache.catalina.StandardServer.initialize().
        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();
        }
    }

【2.2】start() 方法

1)intro:该方法用于启动服务器组件,即启动所有的服务组件,逐个启动所有组件,如连接器组件和servlet容器;

 public void start() throws LifecycleException {  //org.apache.catalina.StandardServer.start().
        // 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);
    }

【2.3】stop()方法

1)intro:用于关闭服务器组件;(调用stop方法会关闭所有的服务组件,并reset started,这样,才能再次启动服务器组件;参见start()方法)

public void stop() throws LifecycleException {   //org.apache.catalina.StandardServer.stop().

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

【2.4】await()方法

1)intro:该方法负责等待关闭整个tomcat 部署的命令;

2)await()方法:调用该方法后,会一直阻塞,直到它从 8085 端口(也可以是其他端口)上接收到关闭命令(accept()方法);当await()方法返回时,会运行stop方法来关闭其下的所有子组件;

public void await() {  //org.apache.catalina.StandardServer.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(); //highlight line.
                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); //highlight line.
            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) {
            ;
        }
    }

对以上代码的调用过程分析(steps):

step1)创建一个ServerSocket对象,监听8085端口,并在while循环中调用它的accept()方法;

step2)当在指定端口上接收到消息时,accept()方法才会返回;

step3)将接收到的消息与关闭命令的字符串相比较,相同的话就跳出while循环,关闭 ServerSocket,否则会再次循环,继续等待消息;

【3】Service接口(服务组件接口——org.apache.catalina.core.Service)

1)intro:一个服务组件可以有一个servlet容器 和 多个连接器实例;(干货——一个服务器组件可以有0个或多个服务组件,而一个服务组件可以有一个servlet容器
和 多个连接器实例)

2)可以自由地把连接器添加到服务组件中,所有的连接器都会与这个servlet容器相关联; 

package org.apache.catalina;
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;
}

【4】StandardService类(org.apache.catalina.core.StandardService)

1)StandardService.initialize()方法:用于初始化添加到其中的所有连接器;

2)StandardService.start()方法:启动连接器和所有servlet容器;

【4.1】connectors 和 container

1)StandardService实例中有两种组件:连接器和servlet容器;其中servlet容器只有一个,而连接器则可以有多个;(干货——StandardService实例中有两种组件:连接器和servlet容器)

2)多个连接器使tomcat 可以为多种不同的请求协议提供服务;如,一个连接器处理HTTP请求,而另一个连接器处理HTTPS请求;(干货——多个连接器使tomcat
可以为多种不同的请求协议提供服务)

3)变量connectors 和 container:StandardService类使用 container 变量来指向一个Container接口的实例,而数组connectors 来保存所有连接器的引用;(干货——变量connectors
和 container的用途)

 private Connector connectors[] = new Connector[0]; // defined in StandardService.

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

public void setContainer(Container container) { // org.apache.catalina.core.StandardService.setContainer().
        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);
    }

对以上代码的补充描述(description):与服务组件相关联的servlet容器的实例将被传给每个连接器对象的 setContainer()方法,这样在服务组件中就可以形成每个连接器和 servlet容器间的关联关系;

5)addConnector()方法和removeConnector()方法:前者将连接器添加到服务组件中, 后者将某个连接器移除;

(补充:addConnector()方法会初始化并启动添加到其中的连接器,参见下面的start()方法——highlight line.)

public void addConnector(Connector connector) { //org.apache.catalina.core.StandardService.addConnector().
        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(); //highlight line.
                } catch (LifecycleException e) {
                    e.printStackTrace(System.err);
                }
            }

            if (started && (connector instanceof Lifecycle)) {
                try {
                    ((Lifecycle) connector).start();//highlight line.
                } catch (LifecycleException e) {
                    ;
                }
            }
            // Report this property change to interested listeners
            support.firePropertyChange("connector", null, connector);
        }
    }
public void removeConnector(Connector connector) {  //org.apache.catalina.core.StandardService.removeConnector().
        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);
        }
    }

【4.2】与生命周期有关的方法(start() + stop() + initialize())

1)intro: 与生命周期有关的方法包括Lifecycle.start() + Lifecycle.stop()+ initialize()方法;其中initialize()方法会调用该服务组件中所有连接器的 initialize()方法;

2)org.apache.catalina.core.StandardService.initialize()源码如下:

public void initialize()  throws LifecycleException {  //org.apache.catalina.core.StandardService.initialize().
        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(); //highlight line.
                }
        }
    }
public void initialize()  throws LifecycleException { //org.apache.catalina.connector.HttpConnector.initialize().
        if (initialized)
            throw new LifecycleException (
                sm.getString("httpConnector.alreadyInitialized"));
        this.initialized=true;
        Exception eRethrow = null;
        // Establish a server socket on the specified port
        try {
            serverSocket = open();
        } catch (IOException ioe) {
            log("httpConnector, io problem: ", ioe);
            eRethrow = ioe;
        } catch (KeyStoreException kse) {
            log("httpConnector, keystore problem: ", kse);
            eRethrow = kse;
        } catch (NoSuchAlgorithmException nsae) {
            log("httpConnector, keystore algorithm problem: ", nsae);
            eRethrow = nsae;
        } catch (CertificateException ce) {
            log("httpConnector, certificate problem: ", ce);
            eRethrow = ce;
        } catch (UnrecoverableKeyException uke) {
            log("httpConnector, unrecoverable key: ", uke);
            eRethrow = uke;
        } catch (KeyManagementException kme) {
            log("httpConnector, key management problem: ", kme);
            eRethrow = kme;
        }
        if ( eRethrow != null )
            throw new LifecycleException(threadName + ".open", eRethrow);
    }

3)org.apache.catalina.core.StandardService.start()源码如下:该方法负责启动被添加到 该服务组件中的连接器和servlet容器;

 public void start() throws LifecycleException {  // org.apache.catalina.core.StandardService.start()
        // 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(); //highlight line.
                }
            }
        }
        // Start our defined Connectors second
        synchronized (connectors) {
            for (int i = 0; i < connectors.length; i++) {
                if (connectors[i] instanceof Lifecycle)
                    ((Lifecycle) connectors[i]).start(); //highlight line.
            }
        }
        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_START_EVENT, null);
    }

4)org.apache.catalina.core.StandardService.stop()源码如下:用于关闭与该服务组件相关联的servlet容器和所有连接器;

public void stop() throws LifecycleException { // org.apache.catalina.core.StandardService.stop()
        // 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();//highlight line.
            }
        }
        // Stop our defined Container second
        if (container != null) {
            synchronized (container) {
                if (container instanceof Lifecycle) {
                    ((Lifecycle) container).stop(); //highlight line.
                }
            }
        }
        // Notify our interested LifecycleListeners
        lifecycle.fireLifecycleEvent(AFTER_STOP_EVENT, null);
    }

【5】应用程序 

1)intro:本应用程序旨在说明如何使用服务器组件和服务组件,特别是在 StandardServer类中如何利用 启动和关闭机制;

2)共有3个类:Bootstrap类+Stopper类+SimpleContextConfig类(它其实是作为 LifecycleListener的实例)

2.1)Bootstrap类源码

public final class Bootstrap {
  public static void main(String[] args) {

    System.setProperty("catalina.base", System.getProperty("user.dir"));
    Connector connector = new HttpConnector();

    Wrapper wrapper1 = new StandardWrapper();
    wrapper1.setName("Primitive");
    wrapper1.setServletClass("PrimitiveServlet");
    Wrapper wrapper2 = new StandardWrapper();
    wrapper2.setName("Modern");
    wrapper2.setServletClass("ModernServlet");

    Context context = new StandardContext();
    // StandardContext's start method adds a default mapper
    context.setPath("/app1");
    context.setDocBase("app1");

    context.addChild(wrapper1);
    context.addChild(wrapper2);

    LifecycleListener listener = new SimpleContextConfig();
    ((Lifecycle) context).addLifecycleListener(listener);

    Host host = new StandardHost();
    host.addChild(context);
    host.setName("localhost");
    host.setAppBase("webapps");

    Loader loader = new WebappLoader();
    context.setLoader(loader);
    // context.addServletMapping(pattern, name);
    context.addServletMapping("/Primitive", "Primitive");
    context.addServletMapping("/Modern", "Modern");

    Engine engine = new StandardEngine();
    engine.addChild(host);
    engine.setDefaultHost("localhost");

    Service service = new StandardService();
    service.setName("Stand-alone Service");
    Server server = new StandardServer();
    server.addService(service);
    service.addConnector(connector);

    //StandardService class's setContainer will call all its connector's setContainer method
    service.setContainer(engine);

    // Start the new server
    if (server instanceof Lifecycle) {
      try {
        server.initialize();
        ((Lifecycle) server).start();
        server.await();
        // the program waits until the await method returns,
        // i.e. until a shutdown command is received.
      }
      catch (LifecycleException e) {
        e.printStackTrace(System.out);
      }
    }

    // Shut down the server
    if (server instanceof Lifecycle) {
      try {
        ((Lifecycle) server).stop();
      }
      catch (LifecycleException e) {
        e.printStackTrace(System.out);
      }
    }
  }
}

对以上代码的调用过程分析(steps):

step1)该方法会创建一个连接器,两个Wrapper实例,一个Context容器,一个Host容器和一个Engine容器;

step2)将两个Wrapper 实例添加到 Context容器中, 将Context容器添加到 Host容器中,再将Host容器添加到Engine容器中;(干货——到此,tomcat的4种容器创建完毕)

step3)但是,这并没有将连接器和最顶层的容器Engine相关联;

step4)相反,main()方法创建了一个Service对象,设置其名称,再创建一个 Server对象,将Service实例添加到 Server实例中:

 Service service = new StandardService();
    service.setName("Stand-alone Service");
    Server server = new StandardServer();
    server.addService(service);

step5)main()方法将连接器和Engine容器添加到 Service实例中;

    service.addConnector(connector);
    service.setContainer(engine);

step6)main()方法调用 Server.intialize() 和 Server.start()方法,初始化连接器,并启动连接器和servlet容器;

step7)接下来,main()方法调用Server.await()方法,进入循环等待,监听8085端口等待关闭命令;(干货——参见上述【2.4】await()方法)

Attention)此时连接器已经处于运行状态,等待另一个端口8080上的 http 请求;(监听8085和8080端口分别处于不同的线程)

// Start the new server
    if (server instanceof Lifecycle) {
      try {
        server.initialize(); // step6
        ((Lifecycle) server).start(); // step6
        server.await(); // step7
        // the program waits until the await method returns,
        // i.e. until a shutdown command is received.
      }
      catch (LifecycleException e) {
        e.printStackTrace(System.out);
      }
    }

step8)除非收到了正确的关闭命令,否则await()方法是不会返回的。当 await()方法返回时,main()方法调用 Server.stop()方法,实际上关闭其所有组件;

// Shut down the server
    if (server instanceof Lifecycle) {
      try {
        ((Lifecycle) server).stop();
      }
      catch (LifecycleException e) {
        e.printStackTrace(System.out);
      }
    }

2.2)Stopper类 源码

2.2.1)intro: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.");
    }
  }
}

对以上代码的分析(Analysis): Stopper类的main()方法会创建一个 Socket对象,然后将正确 的关闭命令 “SHOTDOWN”字符串发送到 端口8085。Catalina 服务器在接收到关闭命令后,就会执行相应的关闭操作;

Attention)本文还是习惯性地总结了上述测试用例的调用流程图

A1)HttpConnector.start()方法的调用过程如下(下面的图借用自 tomcat(11) 中章节【1】的4.1小节的图):

A2)StandardsEngine.start()方法的调用过程如下(下面的第二张图借用自tomcat(13)中的章节【10】 ,两张图可以结合起来看):

(补充,需要了解 HttpConnector.initialize()
和 start() 方法 以及 StandardContext.start()方法的具体调用过程,参见
 tomcat(supplement)HttpConnector.initialize() 和 start() 方法 以及 StandardContext.start()方法的分析

【6】执行结果

1)console info

E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src>java -cp .;lib/servlet.jar;lib/catalina_4_1_24.jar;lib/catalina-5.5.4.jar;lib/naming-common.
jar;lib/commons-collections.jar;lib/naming-resources.jar;lib/commons-digester.jar;lib/catalina.jar;E:\bench-cluster\cloud-data-preprocess\HowTomcatWok
s\weroot com.tomcat.chapter14.startup.Bootstrap
HttpConnector Opening server socket on all host IP addresses
Starting service Stand-alone Service
Apache Tomcat/4.1.24
WebappLoader[/app1]: Deploying class repositories to work directory E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src\work\_\localhost\app1
WebappLoader[/app1]: Deploy class files /WEB-INF/classes to E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src\webapps\app1\WEB-INF\classes
StandardManager[/app1]: Seeding random number generator class java.security.SecureRandom
StandardManager[/app1]: Seeding of random number generator has been completed
StandardManager[/app1]: IOException while loading persisted sessions: java.io.EOFException
java.io.EOFException
        at java.io.ObjectInputStream$PeekInputStream.readFully(Unknown Source)
        at java.io.ObjectInputStream$BlockDataInputStream.readShort(Unknown Source)
        at java.io.ObjectInputStream.readStreamHeader(Unknown Source)
        at java.io.ObjectInputStream.<init>(Unknown Source)
        at org.apache.catalina.util.CustomObjectInputStream.<init>(CustomObjectInputStream.java:103)
        at org.apache.catalina.session.StandardManager.load(StandardManager.java:408)
        at org.apache.catalina.session.StandardManager.start(StandardManager.java:655)
        at org.apache.catalina.core.StandardContext.start(StandardContext.java:3570)
        at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1188)
        at org.apache.catalina.core.StandardHost.start(StandardHost.java:738)
        at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1188)
        at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:347)
        at org.apache.catalina.core.StandardService.start(StandardService.java:497)
        at org.apache.catalina.core.StandardServer.start(StandardServer.java:2190)
        at com.tomcat.chapter14.startup.Bootstrap.main(Bootstrap.java:77)
StandardManager[/app1]: Exception loading sessions from persistent storage
java.io.EOFException
        at java.io.ObjectInputStream$PeekInputStream.readFully(Unknown Source)
        at java.io.ObjectInputStream$BlockDataInputStream.readShort(Unknown Source)
        at java.io.ObjectInputStream.readStreamHeader(Unknown Source)
        at java.io.ObjectInputStream.<init>(Unknown Source)
        at org.apache.catalina.util.CustomObjectInputStream.<init>(CustomObjectInputStream.java:103)
        at org.apache.catalina.session.StandardManager.load(StandardManager.java:408)
        at org.apache.catalina.session.StandardManager.start(StandardManager.java:655)
        at org.apache.catalina.core.StandardContext.start(StandardContext.java:3570)
        at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1188)
        at org.apache.catalina.core.StandardHost.start(StandardHost.java:738)
        at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1188)
        at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:347)
        at org.apache.catalina.core.StandardService.start(StandardService.java:497)
        at org.apache.catalina.core.StandardServer.start(StandardServer.java:2190)
        at com.tomcat.chapter14.startup.Bootstrap.main(Bootstrap.java:77)
HttpConnector[8080] Starting background thread
ModernServlet -- init
StandardHost[localhost]: MAPPING configuration error for request URI /favicon.ico

2)执行效果

时间: 2024-08-06 22:03:23

tomcat(14)服务器组件和服务组件的相关文章

Tomcat中的服务器组件和 服务组件

开始学习Tocmat时,都是学习如何通过实例化一个连接器 和 容器 来获得一个Servlet容器,并将连接器  和 servlet容器相互关联,但是之前学习的都只有一个连接器可以使用,该连接器服务8080端口上的HTTP请求,无法添加另一个连接器来服务 诸如 HTTPS之类的其他请求,而且前面所有学的示例,都缺少一种启动或者 关闭servlet容器的机制,那么下面学习一下提供这两种机制的特性的组件,分别是服务器组件 和 服务组件. 服务器组件. org.apahce.catalina.Serve

How tomcat works 读书笔记十四 服务器组件和服务组件

之前的项目还是有些问题的,例如 1 只能有一个连接器,只能处理http请求,无法添加另外一个连接器用来处理https. 2 对容器的关闭只能是粗暴的关闭Bootstrap. 服务器组件 org.apache.catalina.Server接口的实例用来表示Catalina的整个servlet引擎. 我们使用Server就是因为,它用一种优雅的方式来启动/关闭整个系统. 下面是启动和停止机制是如何工作的.当服务器启动的时候,它启动它内部的所有组件.然后无限期的等待关闭命令,如果你想要关闭系统,发送

1.4 主要组件与服务

1.4  主要组件与服务 SQL Server 不仅仅是数据库的概念,除了提供数据库引擎之外,还有一套完整的商业智能解决方案.商业智能还需要使用 SQL Server 的另外三个服务:集成服务(SQL Server Integration Services,简称 SSIS).分析服务(SQL Server Analysis Services,简称 SSAS).报表服务(SQL Server Reporting Services,简称 SSRS). 1.4.1  实例 实例可以看作是 SQL Se

6.安装和配置OpenStack图片服务组件

安装和配置图片服务组件 这里是安装在控制器上 安装和配置图片服务组件 yum install –y openstack-glance python-glanceclient 编辑/etc/glance/glance-api.conf mv /etc/glance/glance-api.conf /etc/glance/glance-api.conf_bak vim /etc/glance/glance-api.conf [database] connection = mysql://glance

Hortonworks HDP Sandbox定制(配置)开机启动服务(组件)

定制Hortonworks HDP开机启动服务可以这样做:本文原文出处: http://blog.csdn.net/bluishglc/article/details/42109253 严禁任何形式的转载,否则将委托CSDN官方维护权益! 找到文件:/usr/lib/hue/tools/start_scripts/start_deps.mf,Hortonworks HDP启动所有服务和组件的命令都在这个文件中,之所以把这些服务的启动命令写在了一个makefile中而不是一个shell文件,其实就

excel导入 服务器忘了装组件了。。。

excel导入 本地没问题 一直在找权限问题  最后发现服务器忘了装组件了... 郁闷 记录下 http://www.microsoft.com/zh-cn/download/confirmation.aspx?id=13255 string strCon = "Provider=Microsoft.Ace.OleDb.12.0;Data Source=" + filepath + ";Extended Properties='Excel 12.0;HDR=YES;IMEX=

构建简单的 C++ 服务组件,第 1 部分: 服务组件体系结构 C++ API 简介

构建简单的 C++ 服务组件,第 1 部分: 服务组件体系结构 C++ API 简介 熟悉将用于 Apache Tuscany SCA for C++ 的 API.您将通过本文了解该 API 的主要组成部分,以便快速入门. 查看本系列更多内容 | 0 评论: Ed Slattery ([email protected]), 软件工程师, IBM UK Pete Robbins ([email protected]), 软件工程师, IBM UK Andrew Borley ([email pro

MVC扩展Filter,通过继承HandleErrorAttribute,使用log4net或ELMAH组件记录服务端500错误、HttpException、Ajax异常等

□ 接口 public interface IExceptionFilter{    void OnException(ExceptionContext filterContext);} ExceptionContext继承于ControllerContext,从中可以获得路由数据route data.HttpContext. □ 的HandleErrorAttribute是对IExceptionFilter的实现,默认是启用的 public static void RegisterGlobal

HTTP协议级消息队列服务组件UCMQ

UCMQ是一款轻量的HTTP协议级消息队列服务组件,项目的最初原型来自"张宴"的HTTPSQS. 基本特性: 支持标准的HTTP协议( GET/POST方法),支持长连接(keep-alive): 请求响应非常快速,入队列.出队列速度超过10000次/秒: 每个UCMQ实例支持多队列,队列通过操作接口自动创建: 单个队列默认限制存储100w未读消息,可以不限制(非必要建议限制): 可以在不停止服务的情况下便捷地修改单个队列的属性(大小限制/只读锁/延时队列/同步频率): 可以实时查看队