生命周期处理器
AbstractApplicationContext->refresh():
// 最后一步,发布相应的事件
finishRefresh();
ServletWebServerApplicationContext->finishRefresh():
super.finishRefresh();
// web服务开启监听
WebServer webServer = startWebServer();
if (webServer != null) {
// ServletWebServerInitializedEvent事件
publishEvent(new ServletWebServerInitializedEvent(webServer, this));
}
复制代码
super.finishRefresh()
调用的是AbstractApplicationContext
的finishRefresh()
方法。
initLifecycleProcessor()
:初始化上下文中的生命周期处理器,若IoC容器中没有的话,则默认为DefaultLifecycleProcessor
对象
getLifecycleProcessor().onRefresh()
:找到IoC容器中实现Lifecycle
接口的bean,如果是SmartLifecycle
接口实现类且isAutoStartup()
方法返回true,isRunning()
方法返回false的话,执行start()
方法。
publishEvent(new ContextRefreshedEvent(this))
:ContextRefreshedEvent
事件,启动定时任务
监听
service与connector的解绑与重绑
前情回顾:Tomcat启动时service与connector的解绑
所谓的解绑,就是将service中的connector移除,将两者的关系放到TomcatWebServer
的serviceConnectors变量中留作后用
TomcatWebServer->start():
// 添加之前移除过的connectors
addPreviouslyRemovedConnectors(); // --1
......
// 检查所有的connector正常启动
checkThatConnectorsHaveStarted();
TomcatWebServer->addPreviouslyRemovedConnectors():
Service[] services = this.tomcat.getServer().findServices();
for (Service service : services) {
Connector[] connectors = this.serviceConnectors.get(service);
if (connectors != null) {
for (Connector connector : connectors) {
service.addConnector(connector);
}
this.serviceConnectors.remove(service);
}
}
StandardService->addConnector():
// service与connector相互绑定
......
// 注意到第一次绑定的时候状态是NEW,此时是STARTED,所以走if方法
if (getState().isAvailable()) {
connector.start();
}
复制代码
connector、http11NioProtocol、nioEndpoint的启动
在connector的startInternal()
中,Http11NioProtocol
启动,它又将NioEndpoint
启动
AbstractEndpoint->start():
bindWithCleanup(); // --1
startInternal(); // --2
NioEndpoint->bind(): // --1
initServerSocket();
......
// 初始化NioSelectorPool相关属性,与最终写入和输出到客户端有关
selectorPool.open();
// 终于在这边找到了监听的代码
NioEndpoint->initServerSocket():
serverSock = ServerSocketChannel.open();
socketProperties.setProperties(serverSock.socket());
InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
// 绑定端口号,注意,如果端口号被占用,将会抛出异常
serverSock.socket().bind(addr,getAcceptCount());
// 此时请求就通了
NioEndpoint->startInternal(): // --2
......
if ( getExecutor() == null ) {
// 创建任务执行线程池
createExecutor();
pollers = new Poller[getPollerThreadCount()];
// Poller负责轮训事件栈
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();
}
// Acceptor主要用来监听是否有客户端连接进来并接收连接
startAcceptorThreads();
// 至此,响应就通了
}
复制代码
在Http11NioProtocol模型之NioEndpoint中介绍过Acceptor、Poller和Executor,作用顺序是从前往后,创建顺序正好与之相反。
总结
所谓的监听,其实就是connector的启动。SpringIoC先实例化与web服务有关的bean,然后再实例化普通bean,Tomcat启动时,普通bean尚未实例化,此时不能开启监听接受请求,因此先将两者解绑,待普通bean实例化完成后,再重新绑定,开启监听,接受请求和响应。
销毁
web服务器销毁的入口方法位于TomcatWebServer->stop():stopTomcat()
销毁分为两步,第一步是停止,第二步是销毁。
与启动一样,也是各组件按照顺序进行的。如下图所示,每个组件的生命周期独立。这里的组件2是组件1的最后一个组件,组件3是组件2的最后一个组件,以此类推。
各组件顺序为和大致作用为:
- nioEndpoint(关闭监听)
- wrapper、context、host、engine
- engine、host、conext的子组件异步停止,wrapper同步停止
- 中断背景线程
- nioEndpoint、http11NioProtocol、connector
- service、server