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.)