Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the source code of NIO in Tomcat

2025-02-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Servers >

Share

Shulou(Shulou.com)05/31 Report--

This article introduces the relevant knowledge of "what is the source code of NIO in Tomcat". In the operation of actual cases, many people will encounter such a dilemma, so let the editor lead you to learn how to deal with these situations. I hope you can read it carefully and be able to achieve something!

First, draw a simple picture to illustrate the main content of this article:

Catalogue

Source code environment preparation

Since the source code of the tomcat downloaded above is not organized with maven, it is not convenient for us to look at the source code and debug it. Here we will use tomcat-embed-core in the maven repository to write our own code for startup to debug.

First, create an empty maven project, then add the following dependencies.

Org.apache.tomcat.embed tomcat-embed-core 9.0.6

The above dependencies will only bring in the tomcat-embed-core-9.0.6.jar and tomcat-annotations-api-9.0.6.jar packages, which is enough for this article. If you need other features, you need to refer to other dependencies, such as Jasper.

Then, use the following startup method:

Public static void main (String [] args) throws LifecycleException {Tomcat tomcat = new Tomcat; Connector connector = new Connector ("HTTP/1.1"); connector.setPort (8080); tomcat.setConnector (connector); tomcat.start; tomcat.getServer.await;}

After the above code, our Tomcat starts.

If you are interested in other APIs in Tomcat, please explore on your own, such as setting up webapp directory, setting resources, etc.

Here, I introduce the first important concept: Connector. In Tomcat, using Connector to handle connections, a Tomcat can be configured with multiple Connector to listen on different ports or handle different protocols.

In the construction method of Connector, we can pass HTTP/1.1 or AJP/1.3 to specify the protocol, or we can pass the corresponding protocol processing class. After all, the protocol is not the key point, and it is the right way to match the connections coming in from different ports to different processing classes. Typically, we can specify the following protocol handling classes:

Org.apache.coyote.http11.Http11NioProtocol: corresponding to non-blocking IO

Org.apache.coyote.http11.Http11Nio2Protocol: corresponding to asynchronous IO

Org.apache.coyote.http2.Http2Protocol: corresponding to the http2 protocol, readers who are interested in http2 should quickly look at it.

The focus of this article is of course non-blocking IO. The basics of asynchronous IO have been introduced before. After reading this article, if you are interested in the processing flow of asynchronous IO, you can analyze it yourself.

If you use a version prior to 9.0, Tomcat will automatically configure a connector when it starts, so we don't have to display the configuration.

Version 9.0 Tomcat#start method:

Public void start throws LifecycleException {getServer; server.start;}

Tomcat#start method in version 8.5 and earlier:

Public void start throws LifecycleException {getServer; / / automatically configure a connector getConnector; server.start; that uses non-blocking IO}

Endpoint

We said earlier that a Connector corresponds to a protocol. Of course, this description is not quite correct. Both NIO and NIO2 deal with HTTP/1.1, except that one uses non-blocking and the other uses async. When we go into the specified protocol code, we will find that their code is so simple that it only specifies a specific endpoint.

Opening the Http11NioProtocol and Http11Nio2Protocol source code, we can see that in the constructor, they specify NioEndpoint and Nio2Endpoint, respectively.

/ / non-blocking mode public classHttp11NioProtocolextendsAbstractHttp11JsseProtocol {publicHttp11NioProtocol {/ / NioEndpoint super (new NioEndpoint);}.} / / Asynchronous mode public classHttp11Nio2ProtocolextendsAbstractHttp11JsseProtocol {publicHttp11Nio2Protocol {/ / Nio2Endpoint super (new Nio2Endpoint);}.}

Here is the second important concept: endpoint. Tomcat uses different endpoint to handle different protocol requests, and today we focus on NioEndpoint, which uses non-blocking IO to process HTTP/1.1 protocol requests.

NioEndpoint inheritance = > AbstractJsseEndpoint inheritance = > AbstractEndpoint. The AbstractJsseEndpoint in the middle mainly provides some methods about HTTPS, which we ignore for the time being, and all the later ones about HTTPS are ignored directly. Please analyze by yourself if you are interested.

Init process analysis

Next, let's look at the process from tomcat.start to NioEndpoint.

1. AbstractProtocol # init

@ Override public voidinit throws Exception {... String endpointName = getName; endpoint.setName (endpointName.substring (, endpointName.length-1 1)); endpoint.setDomain (domain); / / name=http-nio-8089,domain=Tomcat endpoint.init; of endpoint}

2. AbstractEndpoint # init

Public final void init throws Exception {if (bindOnInit) {bind; / / here, of course, corresponds to the bind method bindState = BindState.BOUND_ON_INIT;} of the subclass NioEndpoint.}

3. NioEndpoint # bind

Here comes our NioEndpoint, using the knowledge of NIO that we have learned before.

The original code of @ Override public voidbind throws Exception {/ / initServerSocket; is this line. Let's "inline" and say / / turn on ServerSocketChannel serverSock = ServerSocketChannel.open; socketProperties.setProperties (serverSock.socket); / / getPort will return the 8080 we initially set, and get our address of 0.0.0.0 serverSock.socket 8080 InetSocketAddress addr = (getAddressautomatically updated new InetSocketAddress (getAddress,getPort): new InetSocketAddress (getPort)). / / ServerSocketChannel binding address, port, / / the second parameter, backlog, defaults to 100. when it exceeds 100, a new connection will be rejected (but the source code notes also say that the true semantics of this value depends on the specific implementation) serverSock.socket.bind (addr,getAcceptCount); / / the ServerSocketChannel is set to blocking mode "blocking" serverSock.configureBlocking (true) / / set the number of acceptor and poller. As to what roles they are, I will say / / acceptorThreadCount defaults to 1 if (acceptorThreadCount = = 0) {/ / FIXME: Doesn't seem to work that well with multiple accept threads / / what the author is trying to say is that using multiple acceptor threads will not result in better performance acceptorThreadCount = 1 } / / number of poller threads. The default value is defined as follows, so in multicore mode, the default is 2 / / pollerThreadCount = Math.min (2cored Runtime.getRuntime.originableProcessors); if (pollerThreadCount Thread.MAX_PRIORITY) {priority = Thread.NORM_PRIORITY;} timeoutThread.setPriority (priority); timeoutThread.setDaemon (true); timeoutThread.start;}

AbstractEndpoint # start

Public final void start throws Exception {/ / according to our process, when we just init, we have already changed bindState to BindState.BOUND_ON_INIT, / / so we will not go into the following if branch: if (bindState = = BindState.UNBOUND) {bind; bindState = BindState.BOUND_ON_START;} / / look at the implementation of NioEndpoint startInternal;}.

The following method is important, and here we will create the acceptor and poller mentioned earlier.

NioEndpoint # startInternal

@ Override public voidstartInternal throws Exception {if (! running) {running = true; paused = false; / / the following are used for caching, and then we will see a lot of such code, in order to reduce the number of new objects coming out 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 a [worker thread pool], and Tomcat wraps the ThreadPoolExecutor itself, / / 1. In order to start corePoolSize threads after creating the thread pool (this belongs to thread pool knowledge, unfamiliar readers can take a look at my previous article) / / 2. Manage the growth mode of the thread pool (default corePoolSize 10, maxPoolSize 200), which is not the focus of this article. Do not analyze if (getExecutor = =) {createExecutor;} / / set a fence (tomcat customizes the class LimitLatch), and control the maximum number of connections. Default is 10000 initializeConnectionLatch. / / start poller threads / / remember that when init was earlier, the number of poller was set to 2 by default, so here start 2 poller threads pollers = new Poller [getPollerThreadCount ()]; for (int iThreads 0; I)

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Servers

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report