上篇写到StandardService.init()

这个方法做什么呢?一起来看看。

这个类也是实现了Lifecycle

如图。这个图中i表示Interface接口。如Lifecycle,Container,Executor

C表示Class类 如StandardService

C上有一个小A表示Abstract Class抽象类 如LifecycleBase,WebappClassLoaderBase

感觉用这个图来表示继承关系很好,但这个不能显示出实现关系。要用类图才可以。

public class StandardService extends LifecycleMBeanBase implements Service

跑题了。。

StandardService和StandardServer一样也是继承自LifecycleMBeanBase

在StandardService没有init方法。

调用的其实是LifecycleBase这个类的init方法,然后会调用StandardService.initInternal()

主要作用:

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

调用预启动初始化。这用于允许connectors绑定到Unix操作环境下的受限端口。

执行LifecycleMBeanBase.initInternal()向MBeanServer类进行MBean(service)组件注册

在这个StandardService的initInternal方法中会先判断container是否为空,

如果不为空则执行container.init()注册container组件(这里的Container是:StandardEngine)

1、初始化所有Executors   

其实就是为Executor指定domain,

然后使用StandardThreadExecutor.initInteral()方法

向MBeanServer注册Executor组件(跟server和service调用init()过程一样)

这里的Executor加载的是org.apache.catalina.core.StandardThreadExecutor类

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

//这里可以略过。。。。
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:
执行提交Runnable任务的对象。该接口提供了一种将任务提交从每个任务的运行机制分解的
方法,包括线程使用,调度等的细节。通常使用执行程序,而不是显式创建线程。例如,您可以
使用以下各项来调用每个新任务
 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:
Executor接口并不严格要求执行是异步的。在最简单的情况下,执行程序可以立即在调用者的线程中运行提交的任务:
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.
更通常地,任务在除调用者的线程之外的一些线程中执行。下面的执行器为每个任务生成一个新的线程。
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.
此包中提供的Executor实现来实现ExecutorService,它是一个更广泛的接口。
ThreadPoolExecutor类提供了一个可扩展的线程池实现。
Executors类为这些Executors执行人员提供了方便的工厂方法。
内存一致性效果:在将Runnable对象提交给执行程序之前,线程中的操作会在其执行开始之前发生,也许在另一个线程中。

2 、初始化Mapper Listener。调用MapperListener.init()方法,跟上面server,service,executor一样注册组件

3   初始化自定义connectors连接器  Initialize our defined Connectors。

同上调用connector.init()注册connector组件

但在connector.initInteral()方法被重写了

代码不长就贴出来吧

@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() &&
!AprLifecycleListener.isAprAvailable()) {
throw new LifecycleException(
sm.getString("coyoteConnector.protocolHandlerNoApr",
getProtocolHandlerClassName()));
} try {
protocolHandler.init();
} catch (Exception e) {
throw new LifecycleException
(sm.getString
("coyoteConnector.protocolHandlerInitializationFailed"), e);
}
}

初始化CoyoteAdapter

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

执行将处理委托给CoyoteAdapter的请求处理器

ProtocolHandler protocolHandler端口处理程序

摘要协议实现,包括线程等。ProtocolHandler 处理器是单线程的,

特定于基于流的协议,不适合像JNI这样的Jk协议。这是由CoyoteAdapter实现的主要接口。

adapter是由coyote servlet container.实现的主要接口。

这个ProtocolHandler是一个接口,调用的ProtocolHandler.init()方法的类是org.apache.coyote.http11.Http11NioProtocol

Note:这里不是用Http11Protocol进行处理,我这个tomcat8.0版本是使用Http11NioProtocol处理器

在Connector构造方法中通过protocolHandlerClassName这个变量来生成处理程序实例

connecto被创建会先设置端口处理程序setProtocol()

这里处理http协议请求的有两个处理器

Http11AprProtocol和Http11NioProtocol前者需要安装复杂环境,后者为默认处理器
/**
* 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();//生成实例 } 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);
}
} }

初始化protocolHandler也就是调用Http11NioProtocol的init方法

public abstract class AbstractProtocol<S> implements ProtocolHandler , MBeanRegistration

有上面可以知道AbstractProtocol实现的ProtocolHandler

--》实际调用

@Override
public void init() throws Exception {
// SSL implementation needs to be in place before end point is
// initialized
必须在end point被初始化之前创建SSL
sslImplementation = SSLImplementation.getInstance(sslImplementationName);
super.init();
}
// Component not pre-registered so register it注册protocolHandler组件
Registry.getRegistry(null, null).registerComponent(this, oname,
null);
//创建thread pool线程池的MBean的名称
tpOname = new ObjectName(domain + ":" +
"type=ThreadPool,name=" + getName());
getName()获得的名字是prefix-address-port
//注册线程池组件
Registry.getRegistry(null, null).registerComponent(endpoint,
tpOname, null);
//Name of MBean for the Global Request Processor.
//注册GlobalRequestProcessor全局请求处理器组件
rgOname=new ObjectName(domain +
":type=GlobalRequestProcessor,name=" + getName());
Registry.getRegistry(null, null).registerComponent(
getHandler().getGlobal(), rgOname, null );
String endpointName = getName();
endpoint.setName(endpointName.substring(, endpointName.length()-));
这里从1开始length-1结束是为了去掉首尾双引号
endpoint.init();

这里执行endpoint是执行的NioEndpoint.init()方法-------在Http11NioProtocol构造方法中设置

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这个类解释
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定制的线程池,提供以下服务:
•套接字线程
•套接字轮询线程
•工作线程池
切换到Java 5时,有机会使用虚拟机的线程池。

NioEndpoint.init()没有重写父类的方法----调用

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

parameter:bindOnInit:默认为true

Controls when the Endpoint binds the port.控制endpoint绑定端口

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 {
面向流的listening socket的可选通道,新创建的服务器套接字通道已打开但尚未绑定。
调用未绑定服务器套接字通道的accept方法的尝试将导致抛出NotYetBoundException。
可以通过调用此类定义的bind方法来绑定服务器套接字通道
serverSock = ServerSocketChannel.open();
socketProperties.setProperties(serverSock.socket());
//实现了ip套接字地址
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
初始化线程计数器
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();
}

到这里在Catalina.load()方法中调用的server.init()已经执行完成。

接下来将调用Catalina.start()方法来调用server.start()启动服务

附:
ObjectName代表一个在domain域下的一个对象名称,或者一个正则对象,这个对象可以通过正则上下文来查询

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

分为三部分:域名,property list属性列表,属性名key

domain:type=ProtocolHandler,port=
提供底层网络I / O的端点必须与ProtocolHandler实现(ProtocolHandler使用BIO,需要BIO端点等)匹配
 

tomcat启动(五)Catalina分析-service.init的更多相关文章

  1. tomcat启动(四)Catalina分析-server的init()方法

    上一回load()方法解析讲到xml解析完成. load()内部接下来会获取server getServer().setCatalina(this); 这个server从createStartDige ...

  2. tomcat启动(六)Catalina分析-StandardServer.start()

    从链接 Tomcat中组件的生命周期管理公共接口Lifecycle 可以知道调用的是StandardServer.startInternal() @Override protected void st ...

  3. tomcat启动(三)Catalina分析-load方法分析

    load()方法按从上到下顺序分析(主要分析本人所没学过的知识点,其它略过...). Digester类作用 使用sax技术对xml进行解析 未开始解析时Digester.push(this)这个用来 ...

  4. [Tomcat 源码分析系列] (二) : Tomcat 启动脚本-catalina.bat

    概述 Tomcat 的三个最重要的启动脚本: startup.bat catalina.bat setclasspath.bat 上一篇咱们分析了 startup.bat 脚本 这一篇咱们来分析 ca ...

  5. tomcat启动(三)Catalina简要分析

    上篇解析Bootstrap到 daemon.setAwait(true); daemon.load(args); daemon.start(); 这三个方法实际是反射调用org.apache.cata ...

  6. tomcat启动批处理——catalina.bat

    这个批处理才是tomcat服务器启动跟关闭的核心脚本.其中包括....(各种变量),此节将详细讲解这个批处理的逻辑. 先看看第一部分脚本: ****************************** ...

  7. Tomcat启动脚本catalina.sh

    1 - 概述脚本catalina.sh用于启动和关闭tomcat服务器,是最关键的脚本另外的脚本startup.sh和shutdown.sh都是使用不同的参数调用了该脚本该脚本的使用方法如下(引自该脚 ...

  8. ubuntu下tomcat启动巨慢分析

    在一个ubuntu14新环境部署tomcat,通过CI启动一个应用时,启动耗时达到15分钟之久.仔细看tomcat输出的耗时统计日志发现如下日志: Creation of SecureRandom i ...

  9. tomcat启动(Ⅶ)请求处理--Processor.process(SocketWrapper<S> socketWrapper)

    tomcat启动(六)Catalina分析-StandardServer.start() 上一篇分析到:Http11NioProcessor.process(SocketWrapper<S> ...

随机推荐

  1. stdafx.h、stdafx.cpp是干什么用的?为什么我的每一个cpp文件都必须包含stdafx.h? Windows和MFC的include文件都非常大,即使有一个快速的处理程序,编

    sstdafx.h.stdafx.cpp是干什么用的?为什么我的每一个cpp文件都必须包含stdafx.h? Windows和MFC的include文件都非常大,即使有一个快速的处理程序,编译程序也要 ...

  2. 绩效沟通的best原则

    绩效沟通-BEST原则 BEST原则指在进行绩效/IDP面谈的时候按照以下步骤进行: 案例:小赵经常在制作标书时候犯错误 Behavior description 描述行为 小赵,8月6日,你制作的标 ...

  3. git 在非空文件夹clone新项目

    在非空目录下 git clone 项目时会提示错误信息: fatal: destination path '.' already exists and is not an empty director ...

  4. mod_pagespeed

    https://github.com/pagespeed/mod_pagespeed.git https://developers.google.com/speed/pagespeed/module/ ...

  5. Sql查询两个时间段有重叠的记录

    这个问题看上去简单,但是想了很久,最后发现,自己的思路有点乱. 下面四条时间段都和最上面那个有重叠的关系,就是这么个意思. 这里是问题的答案: 2个时间: a_start, a_end b_start ...

  6. mysql免安装版 安装配置 (转)

    1. 下载MySQL Community Server 5.6.13 2. 解压MySQL压缩包     将以下载的MySQL压缩包解压到自定义目录下,我的解压目录是:     "D:\Pr ...

  7. BCP 基本语法

    copy from:http://msdn.microsoft.com/zh-cn/library/ms162802.aspx bcp [database_name.] schema.{table_n ...

  8. Python 数据结构与算法——桶排序

    #简单的桶排序 def bucksort(A): bucks = dict() # 定义一个桶变量,类型为字典 for i in A: bucks.setdefault(i,[]) # 每个桶默认为空 ...

  9. WPF 重写微调自带的样式,ListView、DataGrid、TreeView等所有控件的默认样式

    不知道各位在开发中有没有遇到这样的窘迫,开发一个UI,设计给出的效果图和自带的样式的区别很大,然后有的样式通过属性是修改不了的,比如TreeView的子项TreeViewItem,想完全透明背景色就做 ...

  10. requirejs的插件介绍与制作

    本文由作者郑海波授权网易云社区发布. 前言 我这里就不介绍requirejs了, 简而言之: requirejs是支持AMD规范的模块加载器, 事实上它也是AMD的最直接推动者. 现在可供挑选的开源模 ...