zoukankan      html  css  js  c++  java
  • How Tomcat works — 五、tomcat启动(4)

    前面摆了三节的姿势,现在终于要看到最终tomcat监听端口,接收请求了。

    目录

    • Connector
    • Http11Protocol
    • JIoEndpoint
    • 总结

    在前面的初始化都完成之后,进行Connector的初始化,也是执行一些生命周期方法。

    Connector

    在启动过程中这个类的主要作用是初始化并启动CoyoteAdapter和Http11Protocol:

    initInternal

    • 新建一个CoyoteAdapter,并调用protocolHandler.setAdapter方法设置adapter(最后protocol创建processor处理完成之后会调用adapter.service方法)
    • 初始化protocolHandler(在Connector构造函数中就获得了该实例),实际调用的是超类的init方法
    • 初始化mapperListener

    startInternal

    作用很简单了

    • 启动protocolHandler
    • 启动mapperListener

    Http11Protocol

    前面在第一节中说到Connector的时候绘制了tomcat中关于协议的类图,对于不同的协议有不同的连接器,这里主要说关于http11的,ajp也类似。这个类的主要作用就是启动一个JIoEndpoint)(其内部类Acceptor是最终启动线程接收请求的类)。

    特别需要关注的是该构造函数:

    • new JIoEndpoint()
    • new Http11ConnectionHandler(),这个类是Http11Protocol的内部类,负责获取processor来处理请求
    • ((JIoEndpoint)endpoint).setHandler设置endpoint中handler

    init

    虽然是Http11Protocol的实例,但是执行的是父类的init方法,主要的操作在父类的父类的init方法中AbstractProtocol.init

    • 注册MBean
    • 调用JIoEndpoint.init(该类在)初始化JIoEndpoint

    start

    • endpoint.start()启动JIoEndpoint

    JIoEndpoint

    来到了tomcat启动的最后一站,要启动线程监听端口接收请求了。继承关系

    所以也用到了很多父类的方法,这个的作用就是新建socket,绑定到对应端口

    绑定到端口之后,就可以调用socket.accept()接受请求了

    所以startInternal方法主要进行了一下操作

    • 如果Executor(用来执行processor线程)为null则新建
    • 启动Acceptor线程,接受请求就在这个线程里面
    • 启动一个请求超时检测线程JIoEndpoint$AsyncTimeout
    protected class Acceptor extends AbstractEndpoint.Acceptor {
    
        @Override
        public void run() {
    
            int errorDelay = 0;
    
            // Loop until we receive a shutdown command
            while (running) {
    
                // Loop if endpoint is paused
                while (paused && running) {
                    state = AcceptorState.PAUSED;
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        // Ignore
                    }
                }
    
                if (!running) {
                    break;
                }
                state = AcceptorState.RUNNING;
    
                try {
                    //if we have reached max connections, wait
                    countUpOrAwaitConnection();
    
                    Socket socket = null;
                    try {
                        // Accept the next incoming connection from the server
                        // socket
                        socket = serverSocketFactory.acceptSocket(serverSocket);
                    } catch (IOException ioe) {
                        countDownConnection();
                        // Introduce delay if necessary
                        errorDelay = handleExceptionWithDelay(errorDelay);
                        // re-throw
                        throw ioe;
                    }
                    // Successful accept, reset the error delay
                    errorDelay = 0;
    
                    // Configure the socket
                    if (running && !paused && setSocketOptions(socket)) {
                        // Hand this socket off to an appropriate processor
                        if (!processSocket(socket)) {
                            countDownConnection();
                            // Close socket right away
                            closeSocket(socket);
                        }
                    } else {
                        countDownConnection();
                        // Close socket right away
                        closeSocket(socket);
                    }
                } catch (IOException x) {
                    if (running) {
                        log.error(sm.getString("endpoint.accept.fail"), x);
                    }
                } catch (NullPointerException npe) {
                    if (running) {
                        log.error(sm.getString("endpoint.accept.fail"), npe);
                    }
                } catch (Throwable t) {
                    ExceptionUtils.handleThrowable(t);
                    log.error(sm.getString("endpoint.accept.fail"), t);
                }
            }
            state = AcceptorState.ENDED;
        }
    }
    View Code

    终于看到梦寐以求的socket.accept了!虽然只是为了最后这一步,tomcat废了这么多周折,作用还是很重要的:

    • 用来管理生命周期的Lifecycle,给这个容器的生命周期提供了规范和基本实现
    • 便于扩展的容器架构,多Host可用来分布式,多Context部署多个webapp,Wrapper用来作为servlet的直接容器(比如如果是SingleThreadModel的话需要有多个servlet实例)
    • 可以处理多种协议的Connector

    总结

    到这里tomcat 这个启动过程算是完成了,当然了里面还是有很多细节略过了,不过还是很值得仔细进行专题学习,比如:server.xml的解析,web.xml的解析(这样也能明白平时配置的都有什么作用),tomcat的热加载功能是怎么实现的(对的,就在启动过程中启动了一个线程)等等。这些都做了笔记,以后再整理下。

  • 相关阅读:
    《AI for Game Developers》第七章 A*路径寻找算法 (二)(skiplow翻译)
    芯片科普学习笔记
    sprboot 配置logback 日志输出
    springboot+mybatis 配置双数据源(mysql,oracle,sqlserver,db2)
    vue 封装axios请求
    *arg参数
    pytest mac安装了pytest,但是输入pytest却提示命令不存在
    构建Java Web开发环境
    在CentOS上编译安装PostgreSQL
    在Ubuntu 14.04上使用Eclipse开发和调试PosgreSQL9.3.4
  • 原文地址:https://www.cnblogs.com/sunshine-2015/p/5751078.html
Copyright © 2011-2022 走看看