JavaWeb学习之——Tomcat篇Connector

概述

        Tomcat最底层是使用Socket来进行链接的,而Connector的做用就是将接受到的请求转换为Request和Response。Request和Response是按照HTTP协议来封装的,封装完成后就交给Container进行处理。Container处理完成后又返回给Connector,由Connector返给客户端前端

Connector的结构

        Connector主要是经过ProtocolHandler来处理请求的。不用的ProtocolHandler表明不一样的链接类型。例如Http11Protocal使用普通的socket(同步处理),http11NioProtocal使用的NioSocket来连接。ProtocolHandler里面有3个很重要的组件:java

  1. Endpoint:处理最底层的Socket连接(一串字符流)
  2. Processor:用户将Endpoint收到的内容封装成Requst(也就是须要解析HTTP协议)
  3. Adapter将请求适配到合适的Sevlet容器

ProtocolHandler

<!-- 定义一个Connector,在8080端口箭头HTTP的请求 -->
<Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           redirectPort="8443" />
   
<!-- 定义一个Connector,在8009端口箭头AJP的请求 -->
<Connector port="8009" protocol="AJP/1.3" redirectPort="8443" />

在server.xml中就有Connector的配置。图中配置了监听HTTP请求和AJP请求apache

ProtocolHandler有一个抽象实现类AbstractProtocal,下面有3个子类,分别是对Ajp,Http,spdy协议的实现服务器

  • Ajp(apache JServ Protocol),Apache的定向包协议,主要用于前端服务器(如Apache)之间的通讯,他是长链接。
  • Http:略
  • Spdy: 是google开发的协议,效率比Http搞,但使用不普遍

在Connector中默认是使用org.apache.coyote.http11.Http11NioProtocol。app

Endpoint

Endpoint用于处理具体的链接和数据传输,实现是比较复杂的。NioEndpoint集成AnstractEndpoint,AnstractEndpoint也是一个模板类,例如start()方法在AnstractEndpoint中,其中bind()方法由子类去实现socket

public final void start() throws Exception {
        if (bindState == BindState.UNBOUND) {
            bind();
            bindState = BindState.BOUND_ON_START;
        }
        startInternal();
    }
    public abstract void bind() throws Exception;

NioEndpoint的bind()方法就是初始化ServerSocketChannel和Selectorgoogle

public void bind() throws Exception {

        serverSock = ServerSocketChannel.open();
        socketProperties.setProperties(serverSock.socket());
        InetSocketAddress addr = (getAddress()!=null?new InetSocketAddress(getAddress(),getPort()):new InetSocketAddress(getPort()));
        serverSock.socket().bind(addr,getBacklog());
        serverSock.configureBlocking(true); //mimic APR behavior
        serverSock.socket().setSoTimeout(getSocketProperties().getSoTimeout());

        // 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;
        }
        stopLatch = new CountDownLatch(pollerThreadCount);

        // Initialize SSL if needed
        initialiseSsl();

        selectorPool.open();
    }

启动是在startInternal()方法中,主要作了2个事情,初始化Poller线程和Accept线程,Accept负责接收Socket请求,而后具体的处理方法是在Poller线程中。(Accept和Poller是内部类)spa

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

Processor

主要用于处理应用层协议(如HTTP),分别由3个基本协议对应3个基本的抽象类线程

Adapter

Adapter只有一个实现类,就是CoyoteAdapter类。code

  • 把org.apache.coyote包下的Request和Response封装为org.apache.catalina.connector的Request和Response
  • 从Serivce中的Container获取第一个管道,而后调用管道的invoker方法(管道能够理解为一个过滤链,最后会调用StandardWrapperValue来处理Filter和Servlet)
相关文章
相关标签/搜索