Tomcat源码分析之Connector

Connector

全类名:org.apache.catalina.connector.Connector;

构造方法

创建Http11NioProtocol,给成员变量protocolHandler赋值。

也可以根据server.xml的配置,修改指定的protocol

<Connector port="8080" protocol="HTTP/1.1"
               connectionTimeout="20000"
               redirectPort="8443" />
/**
     * Defaults to using HTTP/1.1 NIO implementation.
     */
    public Connector() {
        this("HTTP/1.1");
    }


    public Connector(String protocol) {
        boolean apr = AprStatus.getUseAprConnector() && AprStatus.isInstanceCreated()
                && AprLifecycleListener.isAprAvailable();
        ProtocolHandler p = null;
        try {
            // 没有开启apr,默认创建的是Http11NioProtocol
            p = ProtocolHandler.create(protocol, apr);
        } catch (Exception e) {
            log.error(sm.getString(
                    "coyoteConnector.protocolHandlerInstantiationFailed"), e);
        }
        if (p != null) {
            protocolHandler = p;
            protocolHandlerClassName = protocolHandler.getClass().getName();
        } else {
            protocolHandler = null;
            protocolHandlerClassName = protocol;
        }
        // Default for Connector depends on this system property
        setThrowOnFailure(Boolean.getBoolean("org.apache.catalina.startup.EXIT_ON_INIT_FAILURE"));
    }

init方法

Connector也是一个生命周期类,看看init做了什么?

主要是给protocolHandler设置adapter CoyoteAdapter,这个类用于将接收到的请求进行处理,后面讲请求处理过程时再详细看下这块代码。

还有就是初始化protocolHandler 也即调用Http11NioProtocol的init方法。

@Override
    protected void initInternal() throws LifecycleException {

        super.initInternal();

        // 非核心主流程 省略

        // Initialize adapter
        adapter = new CoyoteAdapter(this);
        protocolHandler.setAdapter(adapter);
        
        // 非核心主流程 省略

        try {
            protocolHandler.init();
        } catch (Exception e) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e);
        }
    }

Http11NioProtocol的构造方法给 创建了一个NioEndpoint并赋值给成员变量endpoint

public Http11NioProtocol() {
        super(new NioEndpoint());
    }

// 父类的构造方法
public AbstractProtocol(AbstractEndpoint<S,?> endpoint) {
        this.endpoint = endpoint;
        setConnectionLinger(Constants.DEFAULT_CONNECTION_LINGER);
        setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
    }

protocolHandler.init(),最终会调到父类AbstractProtocol.init方法,方法里面会调endpoint.init();

下面是endpoint.init()方法

public final void init() throws Exception {
  if (bindOnInit) {
    bindWithCleanup();
    bindState = BindState.BOUND_ON_INIT;
  }
}

// bindWithCleanup 方法最终会调NioEndpoint的bind方法
@Override
public void bind() throws Exception {
  initServerSocket();

  setStopLatch(new CountDownLatch(1));

  // Initialize SSL if needed
  initialiseSsl();
}

NioEndpoint的bind方法会调initServerSocket(),该方法主要会执行:

// 获取一个ServerSocket
serverSock = ServerSocketChannel.open();
socketProperties.setProperties(serverSock.socket());
InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
// 绑定地址,并设置最大可接收连接数,默认100,可在server.xml上修改
serverSock.bind(addr, getAcceptCount());
// 设置阻塞模式
serverSock.configureBlocking(true); //mimic APR behavior

到此,Connector的init方法结束。

start方法

也是调protocolHandler的start方法,即Http11NioProtocol的start方法

@Override
    protected void startInternal() throws LifecycleException {

        // 非核心主流程 省略

        try {
            protocolHandler.start();
        } catch (Exception e) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
        }
    }

会调父类AbstractProtocol的start方法,里面会调endpoint.start();然后会调NioEndpoint的startInternal方法

/**
 * Start the NIO endpoint, creating acceptor, poller threads.
 */
@Override
public void startInternal() throws Exception {

  if (!running) {
    running = true;
    paused = false;

    // 非核心主流程 省略

    // Create worker collection 当接收到请求时会由该线程池处理
    if (getExecutor() == null) {
      createExecutor();
    }

    // 初始化最大可连接数
    initializeConnectionLatch();

    // Start poller thread 启动一个请求事件轮询线程
    poller = new Poller();
    Thread pollerThread = new Thread(poller, getName() + "-Poller");
    pollerThread.setPriority(threadPriority);
    pollerThread.setDaemon(true);
    pollerThread.start();

    // 启动接受连接线程
    startAcceptorThread();
  }
}

核心做了4件事:

1)创建处理请求线程池 createExecutor()

接收到请求会由该线程池处理

public void createExecutor() {
        internalExecutor = true;
        TaskQueue taskqueue = new TaskQueue();
        TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
        // 默认最小10个,最大200个线程
        executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
        taskqueue.setParent( (ThreadPoolExecutor) executor);
    }

2)初始化最大可连接数 initializeConnectionLatch()

protected LimitLatch initializeConnectionLatch() {
        if (maxConnections==-1) {
            return null;
        }
        if (connectionLimitLatch==null) {
            connectionLimitLatch = new LimitLatch(getMaxConnections());
        }
        return connectionLimitLatch;
    }

在接收连接之前会判断是否还可以接收连接,会调用endpoint.countUpOrAwaitConnection();

protected void countUpOrAwaitConnection() throws InterruptedException {
        if (maxConnections==-1) {
            return;
        }
        LimitLatch latch = connectionLimitLatch;
        if (latch!=null) {
            // 会阻塞线程,直到获得一个“连接资格”
            latch.countUpOrAwait();
        }
    }

3)启动一个事件轮询线程Poller

直接看Poller的run方法,run方法核心处理逻辑:

// 会判断是否有新的连接socket事件,有的话将socket注册到selector,并监听读事件
hasEvents = events();

// 检查是否有读事件
keyCount = selector.select(selectorTimeout);

// 处理读请求
processKey(sk, socketWrapper);

4)启动一个监听连接的线程 startAcceptorThread()

protected void startAcceptorThread() {
  acceptor = new Acceptor<>(this);
  String threadName = getName() + "-Acceptor";
  acceptor.setThreadName(threadName);
  Thread t = new Thread(acceptor, threadName);
  t.setPriority(getAcceptorThreadPriority());
  t.setDaemon(getDaemon());
  t.start();
}

会启动Acceptor线程,直接看Acceptor的run方法,核心逻辑:

//if we have reached max connections, wait 达到了最多的连接数,等待
endpoint.countUpOrAwaitConnection();

// 等待获取一个连接
socket = endpoint.serverSocketAccept();

// 处理连接
endpoint.setSocketOptions(socket)
// 增加注册事件,然后由
poller.register(socketWrapper)

endpoint.setSocketOptions(socket),底层会调poller.register(socketWrapper),该方法是会给poller增加一个注册事件,然后由poller run方法扫描到该事件后,将socket注册到selector,并监听读事件

sc.register(getSelector(), SelectionKey.OP_READ, socketWrapper);

到此,Connector启动结束,可以正常接收请求。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值