美文网首页Tomcat
Tomcat 监听初始化流程

Tomcat 监听初始化流程

作者: 晴天哥_王志 | 来源:发表于2018-11-24 08:08 被阅读51次

    开篇

     这篇博文的主要目的是为了理清楚Tomcat监听的初始化流程,所谓的监听初始化流程是指Tomcat启动后直至Accept过程就绪能够监听连接到来为止。

     只有理清楚监听的初始化后流程后才能更好的理解Tomcat处理请求的过程,所以也算是基础的一部分吧。

     整篇博文的思路脉络是先讲解初始化过程中各个组件的关联(架构图+源码),然后讲解清楚初始化的过程(时序图+源码),我想应该是可以讲明白的。

    文末惯例有招聘信息彩蛋。

    组件关联说明

    组件关联

    说明:

      1. Service组件(StandardService)包含Connector组件。
      1. Connector组件包含ProtocolHandler组件。
      1. ProtocolHandler组件包含AbstractEndpoint组件。
      1. Connector包含CoyoteAdapter对象,CoyoteAdapter保存至ProtocolHandler对象。

    StandardService

    public class StandardService extends LifecycleMBeanBase implements Service {
        protected Connector connectors[] = new Connector[0];
    }
    

    说明:

      1. StandardService包含Connector对象。

    Connector

    public class Connector extends LifecycleMBeanBase  {
    
       protected Service service = null;
        protected int port = -1;
        // 默认的protocolHandler的实现类
        protected String protocolHandlerClassName =
            "org.apache.coyote.http11.Http11NioProtocol";
        // protocolHandler对象
        protected final ProtocolHandler protocolHandler;
        // CoyoteAdapter对象
        protected Adapter adapter = null;
    

    说明:

    1. Connector对象包含ProtocolHandler对象。

    ProtocolHandler

    ProtocolHandler类关系图

    说明:

    1. ProtocolHandler具体实现包括ajp和http两类。

    public abstract class AbstractProtocol<S> implements ProtocolHandler,
            MBeanRegistration {
    
        private final AbstractEndpoint<S> endpoint;
        private Handler<S> handler;
    }
    

    说明:

    1. ProtocolHandler的抽象实现类AbstractProtocol包含EndPoint对象。
    public class Http11NioProtocol extends AbstractHttp11JsseProtocol<NioChannel> {
    
        public Http11NioProtocol() {
            super(new NioEndpoint());
        }
    }
    

    说明:

    1. Http11NioProtocol作为ProtocolHandler的实现类之一,注意EndPoint的对象的创建。

    Endpoint


    说明:
      1. AbstractEndpoint的实现类包括NioEndpoint、Nio2Endpoint、AprEndpoint。
    public abstract class AbstractEndpoint<S> {
        protected Acceptor[] acceptors;
        private int port;
        private InetAddress address;
    }
    

    说明:

      1. AbstractEndpoint包含 Acceptor[] acceptors。
      1. AbstractEndpoint包含监听port和address。

    监听初始化流程

    监听初始化流程
    说明:
      1. 监听的初始化过程包括三个阶段,体现在Connector创建&初始化&启动。
      1. Connector创建包括创建Connector、protocolHandler、Endpoint核心对象。
      1. Connector的初始化包括初始化Connector、protocolHandler、Endpoint核心对象。
      1. Connector的启动包括启动Connector、protocolHandler、Endpoint核心对象。
      1. TCP当中经典server端启动过程在Endpoint对象中实现,负责处理连接请求。

    Connector

    public class Connector extends LifecycleMBeanBase  {
        public Connector(String protocol) {
            setProtocol(protocol);
            ProtocolHandler p = null;
            try {
                Class<?> clazz = Class.forName(protocolHandlerClassName);
                p = (ProtocolHandler) clazz.getConstructor().newInstance();
            } catch (Exception e) {
            } finally {
                this.protocolHandler = p;
            }
        }
    
    
    
        protected void initInternal() throws LifecycleException {
            super.initInternal();
            adapter = new CoyoteAdapter(this);
            protocolHandler.setAdapter(adapter);
    
            try {
                protocolHandler.init();
            } catch (Exception e) {
              
            }
        }
    
    
        protected void startInternal() throws LifecycleException {
            setState(LifecycleState.STARTING);
            try {
                protocolHandler.start();
            } catch (Exception e) {
              
            }
        }
    }
    

    说明:

      1. Connector包含创建、初始化、启动三个阶段。
      1. Connector的三个阶段对应protocolHnalder的创建、初始化、启动三个阶段。

    protocolHandler

    public abstract class AbstractProtocol<S> implements ProtocolHandler,
            MBeanRegistration {
    
        private final AbstractEndpoint<S> endpoint;
        private Handler<S> handler;
    
        public AbstractProtocol(AbstractEndpoint<S> endpoint) {
            this.endpoint = endpoint;
            setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
            setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
        }
    
    
        public void init() throws Exception {
            if (getLog().isInfoEnabled()) {
                getLog().info(sm.getString("abstractProtocolHandler.init", getName()));
            }
    
            if (oname == null) {
                // Component not pre-registered so register it
                oname = createObjectName();
                if (oname != null) {
                    Registry.getRegistry(null, null).registerComponent(this, oname, null);
                }
            }
    
            if (this.domain != null) {
                rgOname = new ObjectName(domain + ":type=GlobalRequestProcessor,name=" + getName());
                Registry.getRegistry(null, null).registerComponent(
                        getHandler().getGlobal(), rgOname, null);
            }
    
            String endpointName = getName();
            endpoint.setName(endpointName.substring(1, endpointName.length()-1));
            endpoint.setDomain(domain);
    
            endpoint.init();
        }
    
    
        public void start() throws Exception {
            endpoint.start();
            asyncTimeout = new AsyncTimeout();
            Thread timeoutThread = new Thread(asyncTimeout, getNameInternal() + "-AsyncTimeout");
            int priority = endpoint.getThreadPriority();
            if (priority < Thread.MIN_PRIORITY || priority > Thread.MAX_PRIORITY) {
                priority = Thread.NORM_PRIORITY;
            }
            timeoutThread.setPriority(priority);
            timeoutThread.setDaemon(true);
            timeoutThread.start();
        }
    }
    
    
    public class Http11NioProtocol extends AbstractHttp11JsseProtocol<NioChannel> {
    
        public Http11NioProtocol() {
            super(new NioEndpoint());
        }
    }
    

    说明:

      1. ProtocolHandler包含创建、初始化、启动三个阶段。
      1. ProtocolHandler的三个阶段对应Endpoint的创建、初始化、启动三个阶段。

    Endpoint

    public abstract class AbstractEndpoint<S> {
    
        public void init() throws Exception {
            if (bindOnInit) {
                bind();
                bindState = BindState.BOUND_ON_INIT;
            }
            if (this.domain != null) {
                // Register endpoint (as ThreadPool - historical name)
                oname = new ObjectName(domain + ":type=ThreadPool,name=\"" + getName() + "\"");
                Registry.getRegistry(null, null).registerComponent(this, oname, null);
    
                for (SSLHostConfig sslHostConfig : findSslHostConfigs()) {
                    registerJmx(sslHostConfig);
                }
            }
        }
    
        public final void start() throws Exception {
            if (bindState == BindState.UNBOUND) {
                bind();
                bindState = BindState.BOUND_ON_START;
            }
            startInternal();
        }
    
        public abstract void startInternal() throws Exception;
    
        public abstract void bind() throws Exception;
    }
    

    说明:

      1. Endpoint包含创建、初始化、启动三个阶段。
      1. AbstractEndpoint类板设计模式提供init&start方法。
      1. AbstractEndpoint类init方法实现bind操作,start方法负责启动监听。
    public class NioEndpoint extends AbstractJsseEndpoint<NioChannel> {
    
        public void bind() throws Exception {
    
            if (!getUseInheritedChannel()) {
                serverSock = ServerSocketChannel.open();
                socketProperties.setProperties(serverSock.socket());
                InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
                serverSock.socket().bind(addr,getAcceptCount());
            } else {
                // Retrieve the channel provided by the OS
                Channel ic = System.inheritedChannel();
                if (ic instanceof ServerSocketChannel) {
                    serverSock = (ServerSocketChannel) ic;
                }
                if (serverSock == null) {
                    throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited"));
                }
            }
            serverSock.configureBlocking(true); //mimic APR behavior
    
            // Initialize thread count defaults for acceptor, poller
            if (acceptorThreadCount == 0) {
                // FIXME: Doesn't seem to work that well with multiple accept threads
                acceptorThreadCount = 1;
            }
            if (pollerThreadCount <= 0) {
                //minimum one poller thread
                pollerThreadCount = 1;
            }
            setStopLatch(new CountDownLatch(pollerThreadCount));
    
            // Initialize SSL if needed
            initialiseSsl();
    
            selectorPool.open();
        }
    
        public void startInternal() throws Exception {
    
            if (!running) {
                running = true;
                paused = false;
    
                processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getProcessorCache());
                eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                                socketProperties.getEventCache());
                nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
                        socketProperties.getBufferPool());
    
                // Create worker collection
                if ( getExecutor() == null ) {
                    createExecutor();
                }
    
                initializeConnectionLatch();
    
                // Start poller threads
                pollers = new Poller[getPollerThreadCount()];
                for (int i=0; i<pollers.length; i++) {
                    pollers[i] = new Poller();
                    Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
                    pollerThread.setPriority(threadPriority);
                    pollerThread.setDaemon(true);
                    pollerThread.start();
                }
    
                startAcceptorThreads();
            }
        }
    
    
        protected class Acceptor extends AbstractEndpoint.Acceptor {
            public void run() {
    
                int errorDelay = 0;
    
                while (running) {
                    while (paused && running) {
                        state = AcceptorState.PAUSED;
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            // Ignore
                        }
                    }
    
                    if (!running) {
                        break;
                    }
                    state = AcceptorState.RUNNING;
    
                    try {
                        countUpOrAwaitConnection();
                        SocketChannel socket = null;
                        try {
                            socket = serverSock.accept();
                        } catch (IOException ioe) {
    
                        }
                        errorDelay = 0;
    
                        if (running && !paused) {
                            if (!setSocketOptions(socket)) {
                                closeSocket(socket);
                            }
                        } else {
                            closeSocket(socket);
                        }
                    } catch (Throwable t) {
                    }
                }
                state = AcceptorState.ENDED;
            }
        }
    
    
        protected boolean setSocketOptions(SocketChannel socket) {
            try {
                socket.configureBlocking(false);
                Socket sock = socket.socket();
                socketProperties.setProperties(sock);
    
                NioChannel channel = nioChannels.pop();
                if (channel == null) {
                    SocketBufferHandler bufhandler = new SocketBufferHandler(
                            socketProperties.getAppReadBufSize(),
                            socketProperties.getAppWriteBufSize(),
                            socketProperties.getDirectBuffer());
                    if (isSSLEnabled()) {
                        channel = new SecureNioChannel(socket, bufhandler, selectorPool, this);
                    } else {
                        channel = new NioChannel(socket, bufhandler);
                    }
                } else {
                    channel.setIOChannel(socket);
                    channel.reset();
                }
                getPoller0().register(channel);
            } catch (Throwable t) {
                ExceptionUtils.handleThrowable(t);
                try {
                    log.error("",t);
                } catch (Throwable tt) {
                    ExceptionUtils.handleThrowable(tt);
                }
                // Tell to close the socket
                return false;
            }
            return true;
        }
    
    }
    

    说明:

      1. NioEndpoint是AbstractEndpoint的具体实现类之一。
      1. NioEndpoint实现具体的bind和start方法。
      1. NioEndpoint的Acceptor作为具体的实现负责监听连接。
      1. setSocketOptions负责处理新连接并通过getPoller0().register(channel)注册。

    参考文章

    谈谈 Tomcat 请求处理流程
    Tomcat 请求处理流程详解

    招聘信息

    【招贤纳士】

    欢迎热爱技术、热爱生活的你和我成为同事,和贝贝共同成长。

    贝贝集团诚招算法、大数据、BI、Java、PHP、android、iOS、测试、运维、DBA等人才,有意可投递zhi.wang@beibei.com

    贝贝集团创建于2011年,旗下拥有贝贝网、贝店、贝贷等平台,致力于成为全球领先的家庭消费平台。

    贝贝创始团队来自阿里巴巴,先后获得IDG资本、高榕资本、今日资本、新天域资本、北极光等数亿美金的风险投资。

    公司地址:杭州市江干区普盛巷9号东谷创业园(上下班有多趟班车)

    相关文章

      网友评论

        本文标题:Tomcat 监听初始化流程

        本文链接:https://www.haomeiwen.com/subject/acfaaftx.html