This series of Tomcat for Spring Boot built-in, version 9.0, using Http11NioProtocol.

Jar package information:

<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> < version > 2.1.1. RELEASE < / version > < / dependency >Copy the code

Http11NioProtocol represents HTTP communication in non-blocking mode. During tomcat startup, the NioEndpoint class is initialized. NioEndpoint contains a number of subclasses, most of which are described below.

Acceptor

Acceptor is a thread class that listens for and receives connections from clients.

Acceptor->run(): while (endpoint.isRunning()) { ...... if (! endpoint.isRunning()) { break; } / / endpoint internal packaging LimitLatch object, the default 10000 connections, after calling the following methods, the number of connections + 1, when reached maximum, clog the endpoint. CountUpOrAwaitConnection (); . // The startup phase is set to block, so the method blocks until a client connects, returning the SocketChannel // internal call to serversock.accept (), ServerSock is in NioEndpoint - > initServerSocket () method of initialization socket. = the endpoint serverSocketAccept (); . // Set the channel property if (! The endpoint. SetSocketOptions (socket)) {/ / this method is called, the number of connections - 1 the endpoint. CloseSocket (socket); }Copy the code

The receiver here is a loop that exits only when it is no longer connected

NioEndpoint->setSocketOptions(): // Set this to non-blocking because socket.configureBlocking(false) is used to block all connections to the client; . Channel = niochannels.pop (); if (channel == null) { ...... else { channel.setIOChannel(socket); channel.reset(); } getPoller0().register(channel);Copy the code

When a channel is pulled from the stack, it is determined that if it is empty, it will create a new one, otherwise the corresponding properties will be replaced and reset. This is because NioChannels are frequently generated and eliminated objects, and replacing only properties can greatly save the JVM from creating and reclaiming the entire object, thus optimizing performance. When the event terminates, the close() method is called, at which point nioChannels pushes the socket onto the stack. By default, nioChannels has a maximum of 500 channels, at which point the stack is not pressed and socket.free() is called instead.

Poller

The getPoller0() method gets the Poller class, which, as its name suggests, is responsible for rotating the event stack, first calling the event registration method in acceptors.

NioEndpoint->Poller->register(): PollerEvent r = eventCache.pop(); // From eventCache pop stack, also create a non-null reset for null...... // Press the events stack addEvent(r); NioEndpoint->Poller->run(): // This thread loops indefinitely until destroy() is called while (true) {if (! HasEvents = events(); If (wakeupCounter.getandSet (-1) > 0) {keyCount = selector. SelectNow (); } else { keyCount = selector.select(selectorTimeout); } // set to 0, so the result returned above may be greater than 0; wakeupcounter.set (0); } Iterator<SelectionKey> iterator = keyCount > 0 ? selector.selectedKeys().iterator() : null; while (iterator ! = null && iterator.hasNext()) { SelectionKey sk = iterator.next(); NioSocketWrapper attachment = (NioSocketWrapper)sk.attachment(); if (attachment == null) { iterator.remove(); } else { iterator.remove(); // processKey(sk, attachment); } } timeout(keyCount,hasEvents); } NioEndpoint->Poller->processKey(): if (sk.isReadable()) { if (! processSocket(attachment, SocketEvent.OPEN_READ, true)) { closeSocket = true; }}Copy the code

For details on what the events() method does, click here

Executor

Executor is a task Executor used to process request tasks. SocketProcessorBase is a task definer that defines the execution logic of a task. It is an abstract class that implements an inner class, SocketProcessor, which is NioEndpoint.

AbstractEndpoint->processSocket(): SocketProcessorBase<S> sc = processorCache.pop(); SocketProcessorBase<S> sc = processorCache.pop(); . Executor Executor = getExecutor(); if (dispatch && executor ! = null) { executor.execute(sc); } else { sc.run(); }Copy the code

A task thread pool is created at startup

AbstractEndpoint->createExecutor():
    internalExecutor = true;
    TaskQueue taskqueue = new TaskQueue();
    TaskThreadFactory tf = new TaskThreadFactory(getName() + "-exec-", daemon, getThreadPriority());
    executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), 60, TimeUnit.SECONDS,taskqueue, tf);
    taskqueue.setParent( (ThreadPoolExecutor) executor);
Copy the code

The default attributes of the task execution thread pool are:

  • Number of core threads 10
  • The maximum number of threads is 200
  • The thread name is in the form of HTTP-niO-8080-exec -%d
  • The blocking queue is in first-in, first-out mode, and the number of blocks is the maximum number of Integer threads

summary

So far found in the Http11NioProtocol model

  1. I used a lot ofwhile(true)cycle
  2. Tomcat’s handling of requests is ultimately done inNioEndpointOf the classExecutorThis is why the thread name to execute our business logic is always HTTP-nio-8080-exec -%d
  3. To save on the overhead of object creation and destruction, the policy of creating non-null reset attributes for null is used