Tomcat server及service容器

296 阅读2分钟

Tomcat组件示意图

image.png

server组件

直接看server接口的实现类 StandardServer 通过server.xml配置文件可以看出,Server主要是管理 Service,监听8005端口关闭服务

public void addService(Service service) {
    service.setServer(this);
    synchronized (servicesLock) {
        //复制数组,放置新的service
        Service results[] = new Service[services.length + 1];
        System.arraycopy(services, 0, results, 0, services.length);
        results[services.length] = service;
        services = results;

        if (getState().isAvailable()) {
            try {//启动service组件
                service.start();
            } catch (LifecycleException e) {
                // Ignore
            }
        }
        //触发service属性变化事件
        support.firePropertyChange("service", null, service);
    }

}

public void await() {
    if (port == -2) {//内嵌的Tomcat不需要自身的管理操作,交给spring或者其他内嵌的组件管理即可
        return;
    }
    if (port==-1) {//执行本地变量阻塞等待
        try {
            awaitThread = Thread.currentThread();
            while(!stopAwait) {
                try {
                    Thread.sleep( 10000 );
                } catch( InterruptedException ex ) {
                    // continue and check the flag
                }
            }
        } finally {
            awaitThread = null;
        }
        return;
    }

    // 创建服务端套接字,监听8005端口(server.xml中默认配置的端口)
    try {
        awaitSocket = new ServerSocket(port, 1,
                InetAddress.getByName(address));
    } catch (IOException e) {
        log.error("StandardServer.await: create[" + address
                           + ":" + port
                           + "]: ", e);
        return;
    }

    try {
        awaitThread = Thread.currentThread();

        // Loop waiting for a connection and a valid command
        while (!stopAwait) {
            ServerSocket serverSocket = awaitSocket;
            if (serverSocket == null) {
                break;
            }

            // Wait for the next connection
            Socket socket = null;
            StringBuilder command = new StringBuilder();
            try {
                InputStream stream;
                long acceptStartTime = System.currentTimeMillis();
                try {
                    socket = serverSocket.accept();//接收客户端请求
                    socket.setSoTimeout(10 * 1000);  // 设置超时时间
                    stream = socket.getInputStream();//获取客户端发送的请求字符串
                } catch (SocketTimeoutException ste) {
                    // This should never happen but bug 56684 suggests that
                    // it does.
                    log.warn(sm.getString("standardServer.accept.timeout",
                            Long.valueOf(System.currentTimeMillis() - acceptStartTime)), ste);
                    continue;
                } catch (AccessControlException ace) {
                    log.warn(sm.getString("standardServer.accept.security"), ace);
                    continue;
                } catch (IOException e) {
                    if (stopAwait) {
                        // Wait was aborted with socket.close()
                        break;
                    }
                    log.error(sm.getString("standardServer.accept.error"), e);
                    break;
                }

                // Read a set of characters from the socket
                int expected = 1024; // Cut off to avoid DoS attack
                while (expected < shutdown.length()) {
                    if (random == null) {
                        random = new Random();
                    }
                    expected += (random.nextInt() % 1024);
                }
                while (expected > 0) {
                    int ch = -1;
                    try {
                        ch = stream.read();
                    } catch (IOException e) {
                        log.warn(sm.getString("standardServer.accept.readError"), e);
                        ch = -1;
                    }
                    // Control character or EOF (-1) terminates loop
                    if (ch < 32 || ch == 127) {
                        break;
                    }
                    command.append((char) ch);
                    expected--;
                }
            } finally {
                // Close the socket now that we are done with it
                try {
                    if (socket != null) {
                        socket.close();
                    }
                } catch (IOException e) {
                    // Ignore
                }
            }

            // 匹配字符串 SHUTDOWN,匹配成功直接退出等待
            boolean match = command.toString().equals(shutdown);
            if (match) {
                log.info(sm.getString("standardServer.shutdownViaPort"));
                break;
            } else {
                log.warn(sm.getString("standardServer.invalidShutdownCommand", command.toString()));
            }
        }
    } finally {
        ServerSocket serverSocket = awaitSocket;
        awaitThread = null;
        awaitSocket = null;

        // Close the server socket and return
        if (serverSocket != null) {
            try {
                serverSocket.close();
            } catch (IOException e) {
                // Ignore
            }
        }
    }
}

service组件

protected void initInternal() throws LifecycleException {
    ...
    ...
    // Initialize our defined Connectors 初始化我们定义的Connectors(server.xml中定义)
    synchronized (connectorsLock) {
        for (Connector connector : connectors) {
            try {
                connector.init();
            } catch (Exception e) {
                String message = sm.getString(
                        "standardService.connector.initFailed", connector);
                log.error(message, e);

                if (Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE")) {
                    throw new LifecycleException(message);
                }
            }
        }
    }
}

Connector

server.xml中的配置:<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
               
               
public Connector(String protocol) {
    setProtocol(protocol);//设置客户端和服务端数据通信协议,配置文件中默认HTTP/1.1
    // Instantiate protocol handler
    ProtocolHandler p = null;
    try {//通过反射生成协议处理器
        Class<?> clazz = Class.forName(protocolHandlerClassName);
        p = (ProtocolHandler) clazz.getConstructor().newInstance();
    } catch (Exception e) {
        log.error(sm.getString(
                "coyoteConnector.protocolHandlerInstantiationFailed"), e);
    } finally {
        this.protocolHandler = p;
    }

    if (Globals.STRICT_SERVLET_COMPLIANCE) {
        uriCharset = StandardCharsets.ISO_8859_1;
    } else {
        uriCharset = StandardCharsets.UTF_8;
    }

    // Default for Connector depends on this (deprecated) system property
    if (Boolean.parseBoolean(System.getProperty("org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH", "false"))) {
        encodedSolidusHandling = EncodedSolidusHandling.DECODE;
    }
}

下图是Tomcat协议处理器及端点相关示意图:

image.png