tomcat startup (5) Catalina analysis-service.init

The previous article wrote about StandardService.init()

What does this method do? Lets come look.

This class also implements Lifecycle

As shown in the picture. i in this figure represents the Interface interface. Such as Lifecycle, Container, Executor

C represents Class class such as StandardService

There is a small A on C indicating Abstract Class abstract class such as LifecycleBase, WebappClassLoaderBase

I feel that it is good to use this diagram to represent the inheritance relationship, but this cannot show the implementation relationship. You need to use class diagrams.

public class StandardService extends LifecycleMBeanBase implements Service

I digress. .

StandardService, like StandardServer, also inherits from LifecycleMBeanBase.

There is no init method in StandardService.

What is called is actually the init method of the LifecycleBase class, and then StandardService.initInternal() is called.

main effect:

Invoke a pre-startup initialization. This is used to allow connectors to bind to restricted ports under Unix operating environments.

Call pre-boot initialization. This is used to allow connectors to bind to restricted ports in Unix operating environments.

Execute LifecycleMBeanBase.initInternal() to register the MBean (service) component with the MBeanServer class

In the initInternal method of this StandardService, it will first determine whether the container is empty.

If it is not empty, execute container.init() to register the container component (Container here is: StandardEngine)

1. Initialize all Executors

In fact, it is to specify the domain for the Executor,

Then use the StandardThreadExecutor.initInteral() method

Register the Executor component with MBeanServer (the same process as the server and service calling init())

The Executor here loads the org.apache.catalina.core.StandardThreadExecutor class

public interface Executor extends java.util.concurrent.Executor, Lifecycle

//You can skip this. . . .<br>An object that executes submitted Runnable tasks. This interface provides a
way of decoupling task submission from the mechanics of how each task will be
 run, including details of thread use, scheduling, etc. An Executor is normally
used instead of explicitly creating threads. For example, rather than invoking
new Thread(new(RunnableTask())).start() for each of a set of tasks, you might
use:<br>
The object that executes the submitted Runnable task. This interface provides a way to decompose task submission from the running mechanism of each task.
Methods, including details of thread usage, scheduling, etc. Typically an executor is used instead of explicitly creating a thread. For example, you can
Use the following to invoke each new task
<br>
 Executor executor = anExecutor;
 executor.execute(new RunnableTask1());
 executor.execute(new RunnableTask2());
 ...
 
However, the Executor interface does not strictly require that execution be
asynchronous. In the simplest case, an executor can run the submitted task
immediately in the caller's thread:<br>The Executor interface does not strictly require execution to be asynchronous. In the simplest case, the executor can immediately run the submitted task in the caller's thread:
 class DirectExecutor implements Executor {
   public void execute(Runnable r) {
     r.run();
   }
 }}
More typically, tasks are executed in some thread other than the caller's
thread. The executor below spawns a new thread for each task.
 class ThreadPerTaskExecutor implements Executor {
   public void execute(Runnable r) {
     new Thread(r).start();
   }
 }}
Many Executor implementations impose some sort of limitation on how and
when tasks are scheduled. The executor below serializes the submission of
tasks to a second executor, illustrating a composite executor.<br>More typically, the task executes in some thread other than the caller's thread. The executor below spawns a new thread for each task.
 class SerialExecutor implements Executor {
   final Queue tasks = new ArrayDeque();
   final Executor executor;
   Runnable active;

   SerialExecutor(Executor executor) {
     this.executor = executor;
   }

   public synchronized void execute(final Runnable r) {
     tasks.offer(new Runnable() {
       public void run() {
         try {
           r.run();
         } finally {
           scheduleNext();
         }
       }
     });
     if (active == null) {
       scheduleNext();
     }
   }

   protected synchronized void scheduleNext() {
     if ((active = tasks.poll()) != null) {
       executor.execute(active);
     }
   }
 }}
The Executor implementations provided in this package implement
ExecutorService, which is a more extensive interface. The ThreadPoolExecutor
class provides an extensible thread pool implementation. The Executors class
provides convenient factory methods for these Executors.
Memory consistency effects: Actions in a thread prior to submitting a Runnable
 object to an Executor happen-before its execution begins, perhaps in another
thread.<br>The Executor implementation provided in this package implements ExecutorService, which is a broader interface.<br> The ThreadPoolExecutor class provides an extensible thread pool implementation.<br> The Executors class provides convenient factory methods for these Executors executors.<br>Memory consistency effect: Before the Runnable object is submitted to the executor, operations in the thread occur before its execution begins, perhaps in another thread. 

2. Initialize Mapper Listener. Call the MapperListener.init() method to register components like the server, service, and executor above.

3 Initialize our defined Connectors Initialize our defined Connectors.

Call connector.init() as above to register the connector component

But the connector.initInteral() method was overridden

If the code is not long, please post it.

@Override
    protected void initInternal() throws LifecycleException {

        super.initInternal();

        //Initialize adapter
        adapter = new CoyoteAdapter(this);
        protocolHandler.setAdapter(adapter);

        // Make sure parseBodyMethodsSet has a default
        if( null == parseBodyMethodsSet ) {
            setParseBodyMethods(getParseBodyMethods());
        }

        if (protocolHandler.isAprRequired() & amp; & amp;
                !AprLifecycleListener.isAprAvailable()) {
            throw new LifecycleException(
                    sm.getString("coyoteConnector.protocolHandlerNoApr",
                            getProtocolHandlerClassName()));
        }

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

InitializeCoyoteAdapter

Implementation of a request processor which delegates the processing to a Coyote processor

Execute the request handler that delegates processing to CoyoteAdapter

ProtocolHandler protocolHandler port handler

Abstract protocol implementation, including threads, etc. ProtocolHandler handlers are single-threaded

Specific for stream-based protocols, not suitable for Jk protocols like JNI. This is the main interface implemented by CoyoteAdapter.

Adapter is the main interface implemented by coyote servlet container.

This ProtocolHandler is an interface, and the class called ProtocolHandler.init() method is org.apache.coyote.http11.Http11NioProtocol

Note: Http11Protocol is not used for processing here. My tomcat8.0 version uses the Http11NioProtocol processor

Use the protocolHandlerClassName variable in the Connector constructor to generate a handler instance.

When connecto is created, the port handler setProtocol() will be set first.

There are two processors here that handle http protocol requests.

Http11AprProtocol and <em id="__mceDel">Http11NioProtocol require the installation of a complex environment, while the latter is the default processor</em>
/**
     * Coyote Protocol handler class name.
     * Defaults to the Coyote HTTP/1.1 protocolHandler.
     */
    protected String protocolHandlerClassName =
        "org.apache.coyote.http11.Http11NioProtocol";
public Connector(String protocol) {
?setProtocol(protocol);

Class<?> clazz = Class.forName(protocolHandlerClassName);
p = (ProtocolHandler) clazz.newInstance();//Generate instance

}

public void setProtocol(String protocol) {

        if (AprLifecycleListener.isAprAvailable()) {
            if ("HTTP/1.1".equals(protocol)) {
                setProtocolHandlerClassName
                    ("org.apache.coyote.http11.Http11AprProtocol");
            } else if ("AJP/1.3".equals(protocol)) {
                setProtocolHandlerClassName
                    ("org.apache.coyote.ajp.AjpAprProtocol");
            } else if (protocol != null) {
                setProtocolHandlerClassName(protocol);
            } else {
                setProtocolHandlerClassName
                    ("org.apache.coyote.http11.Http11AprProtocol");
            }
        } else {
            if ("HTTP/1.1".equals(protocol)) {
                setProtocolHandlerClassName
                    ("org.apache.coyote.http11.Http11NioProtocol");
            } else if ("AJP/1.3".equals(protocol)) {
                setProtocolHandlerClassName
                    ("org.apache.coyote.ajp.AjpNioProtocol");
            } else if (protocol != null) {
                setProtocolHandlerClassName(protocol);
            }
        }

    }

Initializing protocolHandler is to call the init method of Http11NioProtocol

public abstract class AbstractProtocol implements ProtocolHandler , MBeanRegistration

You can know the ProtocolHandler implemented by AbstractProtocol as above

–》Actual call

org.
apache.
coyote.
http11.
AbstractHttp11JsseProtocol.init()

@Override
    public void init() throws Exception {
        // SSL implementation needs to be in place before end point is
        // initialized<br>SSL must be created before the end point is initialized<br>
        sslImplementation = SSLImplementation.getInstance(sslImplementationName);
        super.init();
    }

org.
apache.
coyote.
AbstractProtocol.init()

// Component not pre-registered so register it to register the protocolHandler component
Registry.getRegistry(null, null).registerComponent(this, oname,
                    null);
//Create the name of the MBean of the thread pool thread pool
tpOname = new ObjectName(domain + ":" +
                        "type=ThreadPool,name=" + getName());
The name obtained by getName() is prefix-address-port
//Register thread pool component
Registry.getRegistry(null, null).registerComponent(endpoint,
                        tpOname, null);
//Name of MBean for the Global Request Processor.
//Register GlobalRequestProcessor global request processor component
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));
Here starting from 1 and ending with length-1 is to remove the first and last double quotes.
endpoint.init();

The execution endpoint here is the executed NioEndpoint.init() method ——- set in the Http11NioProtocol construction method

public Http11NioProtocol() {
        endpoint=new NioEndpoint();
        cHandler = new Http11ConnectionHandler(this);
        ((NioEndpoint) endpoint).setHandler(cHandler);
        setSoLinger(Constants.DEFAULT_CONNECTION_LINGER);
        setSoTimeout(Constants.DEFAULT_CONNECTION_TIMEOUT);
        setTcpNoDelay(Constants.DEFAULT_TCP_NO_DELAY);
    }

NioEndpoint class explanation

NIO tailored thread pool, providing the following services:
    ?Socket acceptor thread
    ?Socket poller thread
    ?Worker threads pool
When switching to Java 5, there's an opportunity to use the virtual machine's
thread pool.
NIO's customized thread pool provides the following services:
?Socket thread
?Socket polling thread
?Worker thread pool
When switching to Java 5, there is an opportunity to use the virtual machine's thread pool. 

NioEndpoint.init() does not override the parent class method—-call

AbstractEndpoint.init()

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

parameter: bindOnInit: default is true

Controls when the Endpoint binds the port. Controls when the Endpoint binds the port.

true, the default binds the port on init() and unbinds it on destroy().

If set to false the port is bound on start() and unbound on stop().

NioEndpoint.bind()

/**
     * Initialize the endpoint.
     */
    @Override
    public void bind() throws Exception {
Optional channel for stream-oriented listening sockets. The newly created server socket channel is open but not yet bound.<br>An attempt to call the accept method of an unbound server socket channel will result in a NotYetBoundException being thrown.<br>A server socket channel can be bound by calling the bind method defined by this class
        serverSock = ServerSocketChannel.open();
        socketProperties.setProperties(serverSock.socket());<br>//Implemented ip socket address
        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<br>Initialize thread counter<br>
        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
        if (isSSLEnabled()) {
            SSLUtil sslUtil = handler.getSslImplementation().getSSLUtil(this);

            sslContext = sslUtil.createSSLContext();
            sslContext.init(wrap(sslUtil.getKeyManagers()),
                    sslUtil.getTrustManagers(), null);

            SSLSessionContext sessionContext =
                sslContext.getServerSessionContext();
            if (sessionContext != null) {
                sslUtil.configureSessionContext(sessionContext);
            }
            // Determine which cipher suites and protocols to enable
            enabledCiphers = sslUtil.getEnableableCiphers(sslContext);
            enabledProtocols = sslUtil.getEnableableProtocols(sslContext);
        }

        if (oomParachute>0) reclaimParachute(true);
        selectorPool.open();
    }

At this point, the server.init() called in the Catalina.load() method has been executed.

Next, the Catalina.start() method will be called to call server.start() to start the service.

Attachment:

ObjectName represents an object name in the domain domain, or a regular object. This object can be queried through the regular context

tpOname = new ObjectName(domain + “:” + “type=ThreadPool,name=” + getName());

It is divided into three parts: domain name, property list, property name key

domain:type=ProtocolHandler,port=

The endpoint providing the underlying network I/O must match the ProtocolHandler implementation (ProtocolHandler uses BIO, requires BIO endpoints, etc.)

syntaxbug.com © 2021 All Rights Reserved.