SpringBoot應(yīng)用啟動內(nèi)置Tomcat的過程源碼分析
Connector啟動過程
Connector是Tomcat提供的類。
// 通過此 Connector 開始處理請求
@Override
protected void startInternal() throws LifecycleException {
// Validate settings before starting
if (getPortWithOffset() < 0) {
throw new LifecycleException(sm.getString(
"coyoteConnector.invalidPort", Integer.valueOf(getPortWithOffset())));
}
setState(LifecycleState.STARTING);
try {
// 核心動作
protocolHandler.start();
} catch (Exception e) {
throw new LifecycleException(
sm.getString("coyoteConnector.protocolHandlerStartFailed"), e);
}
}
springboot默認(rèn)會在8080端口提供 HTTP 服務(wù),所以這里是一個處理HTTP協(xié)議請求的 Http11NioProtocol 實例,使用 NIO 方式處理 HTTP 協(xié)議。
Connector 對HTTP請求的接收和處理并非親自完成,而是委托該 Http11NioProtocol protocolHandler 完成

而 protocolHandler 又進(jìn)一步將請求處理工作交給 NioEndpoint 完成。
AbstractProtocol
@Override
public void start() throws Exception {
if (getLog().isInfoEnabled()) {
getLog().info(sm.getString("abstractProtocolHandler.start", getName()));
logPortOffset();
}
endpoint.start();
monitorFuture = getUtilityExecutor().scheduleWithFixedDelay(
new Runnable() {
@Override
public void run() {
if (!isPaused()) {
startAsyncTimeout();
}
}
}, 0, 60, TimeUnit.SECONDS);
}
調(diào)用鏈 :
- Connector.start()
- startInternal()
- Http11NioProtocol protocolHandler.start();
- Http11NioProtocol 的 start方法,由基類 AbstractProtocol 提供實現(xiàn)。它們都是tomcat提供的類。
- NioEndpoint endpoint.start()
start成員變量endpoint,一個 NioEndpoint 實例。Http11NioProtocol 類實例也并非最終處理請求,具體這些請求的處理都委托給了 NioEndpint endpoint 來完成

AbstractEndpoint
public final void start() throws Exception {
if (bindState == BindState.UNBOUND) {
bindWithCleanup();
bindState = BindState.BOUND_ON_START;
}
startInternal();
}
可見 tomcat 的三種模式,默認(rèn)使用 NIO 模式。

@Override
public void bind() throws Exception {
initServerSocket();
setStopLatch(new CountDownLatch(1));
// Initialize SSL if needed
initialiseSsl();
selectorPool.open(getName());
}
protected void initServerSocket() throws Exception {
if (!getUseInheritedChannel()) {
// 建立服務(wù)套接字
serverSock = ServerSocketChannel.open();
socketProperties.setProperties(serverSock.socket());
InetSocketAddress addr = new InetSocketAddress(getAddress(), getPortWithOffset());
// 綁定到指定端口
serverSock.socket().bind(addr,getAcceptCount());
} else {
// Retrieve the channel provided by the OS
Channel ic = System.inheritedChannel();
if (ic instanceof ServerSocketChannel) {
serverSock = (ServerSocketChannel) ic;
}
if (serverSock == null) {
throw new IllegalArgumentException(sm.getString("endpoint.init.bind.inherited"));
}
}
// 設(shè)置 serverSock 為阻塞模式
serverSock.configureBlocking(true); //mimic APR behavior
}
serverSocket配置的是阻塞模式,明明默認(rèn)使用NIO 模式,為何還要設(shè)置阻塞模式呢?
為什么使用NIO,因為BIO的accept是阻塞方法,write和read也都是阻塞的。只能當(dāng)新連接到來時,去創(chuàng)建新線程去處理這個連接。如此,最大問題是不能同時處理大量連接,因為大量連接帶來的是創(chuàng)建很多線程,大量線程很容易讓操作系統(tǒng)崩潰,而且雖然并發(fā)度很高,但是很多線程都在空轉(zhuǎn),很多時間都浪費(fèi)在線程空跑和線程切換上,效率也很差。
于是誕生了NIO。
其實處理連接的操作不必放在后臺線程,因為后臺線程很可能會處理連接建立不及時,不如將其置于主線程,增加并發(fā)度(雖然優(yōu)勢并不是特別明顯)。
重點關(guān)心的是連接建立后獲得的與客戶端交互的那個socket,它的操作必須是非阻塞的,這很顯然。因為在處理長連接時,我們關(guān)心的是在本次連接之內(nèi)數(shù)據(jù)的讀寫。
NioEndpoint 正在使用阻塞模式的 ServerSocketChannel 以使其阻塞并等待連接傳入,并且只有在accept后,才以非阻塞方式處理此傳入的socket channel (見setSocketOptions 方法)。
正如作者指出的那樣,使 ServerSocketChannel 成為非阻塞的將導(dǎo)致忙讀取,即一個線程將不斷輪詢有無傳入的連接,因為在非阻塞模式下 accept() 可能返回 null。
APR 代表 Apache Portable Runtime
Tomcat在接收到socket的時候做了如下操作:



參考
https://blog.csdn.net/andy_zhang2007/article/details/78641974
https://stackoverflow.com/questions/23168910/why-tomcats-non-blocking-connector-is-using-a-blocking-socket
到此這篇關(guān)于SpringBoot應(yīng)用啟動內(nèi)置Tomcat的過程分析的文章就介紹到這了,更多相關(guān)SpringBoot 內(nèi)置Tomcat啟動內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決Spring Boot和Feign中使用Java 8時間日期API(LocalDate等)的序列化問題
這篇文章主要介紹了解決Spring Boot和Feign中使用Java 8時間日期API(LocalDate等)的序列化問題,需要的朋友可以參考下2018-03-03
如何使用Comparator比較接口實現(xiàn)ArrayList集合排序
這篇文章主要介紹了如何使用Comparator比較接口實現(xiàn)ArrayList集合排序問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12
深入學(xué)習(xí)java8?中的CompletableFuture
本文主要介紹了java8中的CompletableFuture,CompletableFuture實現(xiàn)了CompletionStage接口和Future接口,前者是對后者的一個擴(kuò)展,增加了異步回調(diào)、流式處理、多個Future組合處理的能力,使Java在處理多任務(wù)的協(xié)同工作時更加順暢便利,下文需要的朋友可以參考一下2022-05-05
SpringCloud創(chuàng)建多模塊項目的實現(xiàn)示例
,Spring Cloud作為一個強(qiáng)大的微服務(wù)框架,提供了豐富的功能和組件,本文主要介紹了SpringCloud創(chuàng)建多模塊項目的實現(xiàn)示例,具有一定的參考價值,感興趣的可以了解一下2024-02-02
java中timer的schedule和scheduleAtFixedRate方法區(qū)別詳解
這篇文章主要為大家詳細(xì)介紹了java中timer的schedule和scheduleAtFixedRate方法區(qū)別,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-12-12
基于springboot實現(xiàn)數(shù)據(jù)可視化的示例代碼
本文主要介紹了基于springboot實現(xiàn)數(shù)據(jù)可視化,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧<BR>2022-07-07

