tomcat启动(六)Catalina分析-StandardServer.start()
从链接
Tomcat中组件的生命周期管理公共接口Lifecycle
可以知道调用的是StandardServer.startInternal()
@Override
protected void startInternal() throws LifecycleException { fireLifecycleEvent(CONFIGURE_START_EVENT, null);
setState(LifecycleState.STARTING); globalNamingResources.start(); // Start our defined Services
synchronized (servicesLock) {
for (int i = 0; i < services.length; i++) {
services[i].start();
}
}
}
1、首先用fireLifecycleEvent()方法发送CONFIGURE_START_EVENT=“config_start”事件
这个事件会被NamingContextListener监听器接收,会为StandardServer的属性globalNamingResources设置监听器为this当前类NamingContextListener
然后生成一个NamingContext命名上下文对象(这个上下文对象联系着JNDI Context)
为StandardServer设置private javax.naming.Context globalNamingContext的值
2、
globalNamingResources.start();这里也发送的一个CONFIGURE_START_EVENT=“config_start”事件
设置状态为starting
/**
* Holds and manages the naming resources defined in the J2EE Enterprise
* Naming Context and their associated JNDI context.
*保存并管理J2EE企业命名上下文中定义的命名资源及其关联的JNDI上下文
* @author Remy Maucherat
*/
public class NamingResourcesImpl extends LifecycleMBeanBase
implements Serializable, NamingResources
3、services[i].start();
这里调用StandardService.startInternal()
/**
* Start nested components ({@link Executor}s, {@link Connector}s and
* {@link Container}s) and implement the requirements of
* {@link org.apache.catalina.util.LifecycleBase#startInternal()}.
*启动嵌套组件StandardThreadExecutor,Connector和StandardEngine
* @exception LifecycleException if this component detects a fatal error
* that prevents this component from being used
*/
@Override
protected void startInternal() throws LifecycleException { if(log.isInfoEnabled())
log.info(sm.getString("standardService.start.name", this.name));
setState(LifecycleState.STARTING); // Start our defined Container first
if (container != null) {
synchronized (container) {
container.start();
}
} synchronized (executors) {
for (Executor executor: executors) {
executor.start();
}
} mapperListener.start(); // Start our defined Connectors second
synchronized (connectorsLock) {
for (Connector connector: connectors) {
try {
// If it has already failed, don't try and start it
if (connector.getState() != LifecycleState.FAILED) {
connector.start();
}
} catch (Exception e) {
log.error(sm.getString(
"standardService.connector.startFailed",
connector), e);
}
}
}
}
1、container.start();
调用的是StandardEngine.startInternal()
2、executor.start();
执行提交的Runnable任务的对象。这个接口提供了一种将任务提交与每个任务如何运行的机制解耦的方法,包括线程使用的细节,调度等。通常使用Executor而不是显式地创建线程。
StandardThreadExecutor:线程执行类。可以看做线程池对象
3、mapperListener.start();
调用MapperListener.startInternal()
用一个变量Mapper mapper持有Host,为StandardEngine和其子Container设置监听器为当前类MapperListener
4、connector.start();
调用Connector。startInternal()
/**
* Begin processing requests via this Connector.
*开始处理请求
* @exception LifecycleException if a fatal startup error occurs
*/
@Override
protected void startInternal() throws LifecycleException { // Validate settings before starting
if (getPort() < 0) {
throw new LifecycleException(sm.getString(
"coyoteConnector.invalidPort", Integer.valueOf(getPort())));
} setState(LifecycleState.STARTING); try {
protocolHandler.start();
} catch (Exception e) {
String errPrefix = "";
if(this.service != null) {
errPrefix += "service.getName(): \"" + this.service.getName() + "\"; ";
} throw new LifecycleException
(errPrefix + " " + sm.getString
("coyoteConnector.protocolHandlerStartFailed"), e);
}
}
protocolHandler.start()
这里默认调用的是Http11NioProtocol。start()
先调用构造方法
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);
}

public abstract class AbstractProtocol<S> implements ProtocolHandler,MBeanRegistration
@Override
public void start() throws Exception {
if (getLog().isInfoEnabled())
getLog().info(sm.getString("abstractProtocolHandler.start",
getName()));
try {
endpoint.start();
} catch (Exception ex) {
getLog().error(sm.getString("abstractProtocolHandler.startError",
getName()), ex);
throw ex;
}
}
endpoint.start()===>调用的是NioEndpoint.startInternal()
/**
* Start the NIO endpoint, creating acceptor, poller threads.启动端点,创建接收器,轮询线程
*/
@Override
public void startInternal() throws Exception { if (!running) {
running = true;
paused = false; 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 worker collection
if ( getExecutor() == null ) {
createExecutor();
} initializeConnectionLatch(); // Start poller threads
pollers = new Poller[getPollerThreadCount()];
for (int i=0; i<pollers.length; i++) {
pollers[i] = new Poller();
Thread pollerThread = new Thread(pollers[i], getName() + "-ClientPoller-"+i);
pollerThread.setPriority(threadPriority);
pollerThread.setDaemon(true);
pollerThread.start();
} startAcceptorThreads();
}
}
上面
1、
processorCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
socketProperties.getProcessorCache());
设置处理器缓存大小:用SynchronizedStack这种LIFO(后进先出)队列存储。默认大小为128,默认处理器缓存最大限制是500。-1是无限制。
eventCache = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
socketProperties.getEventCache());
设置事件缓存大小:默认大小为128,默认事件缓存最大限制是500。-1是无限制。
nioChannels = new SynchronizedStack<>(SynchronizedStack.DEFAULT_SIZE,
socketProperties.getBufferPool());
Bytebuffer cache, each channel holds a set of buffers (two, except for SSL holds four)字节缓冲区缓存,每个通道都包含一组缓冲区(两个,SSL除外)
设置通道缓存大小:默认大小为128,默认通道缓存最大限制是500。-1是无限制。
2、
initializeConnectionLatch();初始化LimintLatch connectionLimitLatch变量。这个变量用来统计endpoint处理的连接数,并限制最大连接数
通过使用LimintLatch这个类实现限制最大socket连接数
tomcat默认的最大连接数位10000
/**
* Shared latch that allows the latch to be acquired a limited number of times
* after which all subsequent requests to acquire the latch will be placed in a
* FIFO queue until one of the shares is returned.
*/
共享锁存器允许获取有限次数的锁存器,之后,所有后续获取锁存器的请求将被置于FIFO队列中,直到其中一个共享被返回。
public class LimitLatch
3、Start poller threads启动轮询线程。线程数通过Math.min(2,Runtime.getRuntime().availableProcessors());这个方法获取最小的处理器数量,使用min方法找到最小值
4startAcceptorThreads启动接收器线程。后台线程监听传入的TCP / IP连接,并将其交给适当的处理器。
这里试着描绘大概流程
startAcceptorThreads()方法会创建Acceptor线程对象
开启线程,循环等待ServerSocket.accept()方法接收到新的连接。然后会将这个socket注册到Poller这个轮询线程。生成一个KeyAttachment对象与socket相关联(后面会用到)
由第3步已经开启的轮询线程,当这个socket发送请求时,Poller线程就收到连接请求后会将
调用NioEndpoint.processSocket(KeyAttachment attachment, SocketStatus status, boolean dispatch)方法,这个方法会开启内部类NioEndpoint.SocketProcessor线程的run()方法
其内部执行调用NioEndpoint.Handler.process(SocketWrapper<NioChannel> socket, SocketStatus status)。---调用的是子类AbstractProtocol.AbstractConnectionHandler.process()
。。。省略一大堆复杂调用。。。。。
最后会调用Http11NioProcessor.process(SocketWrapper<S> socketWrapper)方法中调用CoyoteAdapter.service(request, response);将请求传递到context中。
剩余换一章分析。
到这里tomcat就启动完成了。调用线程等待客户端连接。。。
tomcat启动(六)Catalina分析-StandardServer.start()的更多相关文章
- tomcat启动(三)Catalina分析-load方法分析
load()方法按从上到下顺序分析(主要分析本人所没学过的知识点,其它略过...). Digester类作用 使用sax技术对xml进行解析 未开始解析时Digester.push(this)这个用来 ...
- tomcat启动(五)Catalina分析-service.init
上篇写到StandardService.init() 这个方法做什么呢?一起来看看. 这个类也是实现了Lifecycle 如图.这个图中i表示Interface接口.如Lifecycle,Contai ...
- tomcat启动(四)Catalina分析-server的init()方法
上一回load()方法解析讲到xml解析完成. load()内部接下来会获取server getServer().setCatalina(this); 这个server从createStartDige ...
- [Tomcat 源码分析系列] (二) : Tomcat 启动脚本-catalina.bat
概述 Tomcat 的三个最重要的启动脚本: startup.bat catalina.bat setclasspath.bat 上一篇咱们分析了 startup.bat 脚本 这一篇咱们来分析 ca ...
- Tomcat启动报错:严重: StandardServer.await: create[8005] java.net.BindException: Cannot assign requested address
org.apache.catalina.core.StandardServer await SEVERE: StandardServer.await: create[8005]: ...
- tomcat启动(三)Catalina简要分析
上篇解析Bootstrap到 daemon.setAwait(true); daemon.load(args); daemon.start(); 这三个方法实际是反射调用org.apache.cata ...
- tomcat启动批处理——catalina.bat
这个批处理才是tomcat服务器启动跟关闭的核心脚本.其中包括....(各种变量),此节将详细讲解这个批处理的逻辑. 先看看第一部分脚本: ****************************** ...
- Tomcat启动脚本catalina.sh
1 - 概述脚本catalina.sh用于启动和关闭tomcat服务器,是最关键的脚本另外的脚本startup.sh和shutdown.sh都是使用不同的参数调用了该脚本该脚本的使用方法如下(引自该脚 ...
- ubuntu下tomcat启动巨慢分析
在一个ubuntu14新环境部署tomcat,通过CI启动一个应用时,启动耗时达到15分钟之久.仔细看tomcat输出的耗时统计日志发现如下日志: Creation of SecureRandom i ...
随机推荐
- [LeetCode 总结帖]: 链表专题
链表在笔试面试中都是出镜率极高的一种数据结构. 由于链表具有结构简单,代码量较少,变化多,可以较为全面的考察应聘者的逻辑思考能力以及应变能力的特点,而备受面试官青睐. 在本节中,我将Leetcode中 ...
- linux系统编程之管道(一):匿名管道(pipe)
一,什么是管道 管道是Linux支持的最初Unix IPC形式之一,具有以下特点: 管道是半双工的,数据只能向一个方向流动:需要双方通信时,需要建立起两个管道: 只能用于父子进程或者兄弟进程之间(具有 ...
- android应用搬家的实现
android手机上的应用搬家功能,具体的介绍和原理参考: 系统目录及应用搬家的研究 应用搬家的实现 这里主要是作为一个补充,因为上面两篇文章虽然讲的挺好的,但是给出的例子不能直接运行,还是需要一些准 ...
- Spring Boot 2 实践记录之 使用 Powermock、Mockito 对 UUID 进行 mock 单元测试
由于注册时,需要对输入的密码进行加密,使用到了 UUID.sha1.md 等算法.在单元测试时,使用到了 Powermock,记录如下. 先看下加密算法: import org.apache.comm ...
- C#模拟请求,模拟登录,Cookie设置、文件上传等问题汇总
由于业务需求,最近需要模拟完成登陆某个网站,并上传所需要的文件.在开发途中,遇到了很多问题,现在,就我遇到的一些问题及解决办法说明如下,希望对遇到同样问题的人有所帮助.因为技术有限,可能有些内容并不完 ...
- ASP.NET MVC+Redis (准备工作)
今天准备更新这个项目的第二篇博客.有一点需要说明的是之前觉得用的是Asp.net的WebPage,经过查看微软的官方文档还有相关的博客,相比较而言使用起来需要安装一个自动工具WebMatrix可以很快 ...
- qt中多线程用法总结
1.多线程的理解 在操作系统中线程和进程划分. 操作系统可以同时执行多个任务,每个任务就是进程:进程可以同时执行多个任务,每个任务就是线程. 线程之间相互独立,抢占式执行.对于单核CPU来说同一时刻只 ...
- F#语言入门之什么是F#语言
F#是一种函数式编程语言,可以轻松编写正确且可维护的代码. F#编程主要涉及定义类型推断和自动泛化的类型和函数. 这使您可以将焦点保留在问题域上并操纵其数据,而不是编程的细节. open System ...
- OpenStack 虚机网卡的创建过程
原文链接:https://www.cnblogs.com/potato-chip/p/9127083.html OpenStack虚机网卡的创建过程 OpenStack最基本和常用的操作就是启动虚机. ...
- linux 修改MTU值
Linux系统还可以通过如下方式查看.修改MTU值. 查看:cat /sys/class/net/eth0/mtu 设置:echo "1460" > /sys/class/n ...