Springboot源码分析之内嵌tomcat源码分析
Springboot源碼是內(nèi)嵌tomcat的,這個(gè)和完整的tomcat還是不同。
內(nèi)嵌tomcat的源碼在tomcat-embed-core等3個(gè)jar包里
?展開tomcat-embed-core的catalina目錄
再對(duì)照下載的apache-tomcat-9.0.31源碼
打開bin目錄,看到很多庫(kù)文件比如catalina.jar
再展開看看類文件
和之前Spring內(nèi)嵌的tomcat-embed-core的catalina目錄文件一致。
所以內(nèi)嵌的tomcat只用了一部分代碼。
?
內(nèi)嵌tomcat的配置文件是ServerProperties.java
在org.springframework.boot.autoconfigure.web里,port等配置信息默認(rèn)取這里的。
調(diào)試一下
可以看到最大線程數(shù):maxThreads=200
最大連接數(shù):maxConnections=8192
?
修改最大線程數(shù)和最大連接數(shù)
##端口號(hào)
server.port=8080
server.tomcat.max-threads=300
server.tomcat.max-connections=10000
已經(jīng)改了
?
再看看NIO和APR源碼
在TomcatServletWebServerFactory.java
public class TomcatServletWebServerFactory extends AbstractServletWebServerFactoryimplements ConfigurableTomcatWebServerFactory, ResourceLoaderAware {private static final Charset DEFAULT_CHARSET = StandardCharsets.UTF_8;private static final Set<Class<?>> NO_CLASSES = Collections.emptySet();/*** The class name of default protocol used.*/public static final String DEFAULT_PROTOCOL = "org.apache.coyote.http11.Http11NioProtocol";
private String protocol = DEFAULT_PROTOCOL;
protocol讀取默認(rèn)的DEFAULT_PROTOCOL
啟動(dòng)完成輸出日志看到確實(shí)是NIO:
2020-02-27 12:38:43.264 [main] [INFO ] o.s.boot.web.embedded.tomcat.TomcatWebServer - Tomcat initialized with port(s): 8080 (http)
2020-02-27 12:38:43.277 [main] [INFO ] org.apache.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-8080"]
NIO相對(duì)于BIO已經(jīng)是提升很多, 還可以改為更高效的APR
tomtcat7.0內(nèi)置BIO,8.0,9.0都是NIO。
這三種模式的不同之處如下:
BIO:
【一個(gè)線程處理一個(gè)請(qǐng)求】。
缺點(diǎn):【并發(fā)量高時(shí),線程數(shù)較多,浪費(fèi)資源】。
Tomcat7或以下,在Linux系統(tǒng)中默認(rèn)使用這種方式。
NIO:
【多路復(fù)用】,可以通過【一個(gè)線程處理大量的請(qǐng)求】。
Tomcat8在Linux系統(tǒng)中默認(rèn)使用這種方式。
APR:
即Apache Portable Runtime,從操作系統(tǒng)層面解決io阻塞問題。
Tomcat7或Tomcat8在Win7或以上的系統(tǒng)中啟動(dòng)默認(rèn)使用這種方式。
------------------------------------------------------------------------
Tomcat源碼中與connector相關(guān)的類位于org.apache.coyote包中,Connector分為以下幾類:
Http Connector, 基于HTTP協(xié)議,負(fù)責(zé)建立HTTP連接。它又分為BIO Http Connector與NIO Http Connector兩種,后者提供非阻塞IO與長(zhǎng)連接Comet支持。默認(rèn)情況下,Tomcat使用的就是這個(gè)Connector。
AJP Connector, 基于AJP協(xié)議,AJP是專門設(shè)計(jì)用來為tomcat與http服務(wù)器之間通信專門定制的協(xié)議,能提供較高的通信速度和效率。如與Apache服務(wù)器集成時(shí),采用這個(gè)協(xié)議。
APR HTTP Connector, 用C實(shí)現(xiàn),通過JNI調(diào)用的。主要提升對(duì)靜態(tài)資源(如HTML、圖片、CSS、JS等)的訪問性能。現(xiàn)在這個(gè)庫(kù)已獨(dú)立出來可用在任何項(xiàng)目中。Tomcat在配置APR之后性能非常強(qiáng)勁。
具體地,Tomcat7中實(shí)現(xiàn)了以下幾種Connector:
org.apache.coyote.http11.Http11Protocol : 支持HTTP/1.1 協(xié)議的連接器。
org.apache.coyote.http11.Http11NioProtocol : 支持HTTP/1.1 協(xié)議+New IO的連接器。
org.apache.coyote.http11.Http11AprProtocol : 使用APR(Apache portable runtime)技術(shù)的連接器,利用Native代碼與本地服務(wù)器(如linux)來提高性能。
(以上三種Connector實(shí)現(xiàn)都是直接處理來自客戶端Http請(qǐng)求,加上NIO或者APR)
org.apache.coyote.ajp.AjpProtocol:使用AJP協(xié)議的連接器,實(shí)現(xiàn)與web server(如Apache httpd)之間的通信
org.apache.coyote.ajp.AjpNioProtocol:SJP協(xié)議+ New IO
org.apache.coyote.ajp.AjpAprProtocol:AJP + APR
https://www.cnblogs.com/qq951785919/archive/2013/11/29/3450285.html
------------------------------------
關(guān)于? APR介紹
https://ci.apache.org/projects/tomcat/tomcat9/docs/apr.html?
介紹
Tomcat可以使用Apache Portable Runtime提供出色的可伸縮性,性能以及與本機(jī)服務(wù)器技術(shù)的更好集成。Apache可移植運(yùn)行時(shí)是一個(gè)高度可移植的庫(kù),它是Apache HTTP Server 2.x的核心。APR有許多用途,包括訪問高級(jí)IO功能(例如sendfile,epoll和OpenSSL),操作系統(tǒng)級(jí)別的功能(生成隨機(jī)數(shù),系統(tǒng)狀態(tài)等)和本機(jī)進(jìn)程處理(共享內(nèi)存,NT管道和Unix套接字)。
這些功能使Tomcat成為通用的Web服務(wù)器,可以更好地與其他本機(jī)Web技術(shù)集成,并且總體上使Java作為完善的Web服務(wù)器平臺(tái)而不是僅以后端為中心的技術(shù)更加可行。
安裝
APR支持需要安裝三個(gè)主要的本機(jī)組件:
- APR庫(kù)
- Tomcat使用的APR的JNI包裝器(libtcnative)
- OpenSSL庫(kù)
APR主頁(yè)
https://apr.apache.org/
?
由于本地開發(fā)是基于Windows,Windows下需要二進(jìn)制文件提供給tcnative-1,它是一個(gè)靜態(tài)編譯的.dll,其中包括OpenSSL和APR。在下載對(duì)應(yīng)tomcat包,將bin目錄下的tcnative-1.dll拷貝到j(luò)dk安裝目錄的bin目錄下.
新增配置文件:
import org.apache.catalina.core.AprLifecycleListener;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration
public class AprProtocolConfig {@Beanpublic TomcatServletWebServerFactory servletContainer() {TomcatServletWebServerFactory tomcat = new TomcatServletWebServerFactory();tomcat.setProtocol("org.apache.coyote.http11.Http11AprProtocol");tomcat.addContextLifecycleListeners(new AprLifecycleListener());return tomcat;}
} ?
先初始化TomcatServletWebServerFactory,默認(rèn)的protocol是NIO
?再set為APR
再到TomcatServletWebServerFactory.getWebServer初始化Connector
?反射出org.apache.coyote.http11.Http11AprProtocol
完成初始化
?
ServletWebServerApplicationContext.createWebServer()創(chuàng)建webserver 啟動(dòng)完成輸出APR模型:?
[main] [INFO ] org.apache.coyote.http11.Http11AprProtocol - Initializing ProtocolHandler ["http-apr-8080"][main] [INFO ] org.apache.catalina.core.StandardService - Starting service [Tomcat][main] [INFO ] org.apache.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/9.0.30] ?
下面這兩篇講怎么自定義配置實(shí)現(xiàn)自動(dòng)配置
https://blog.csdn.net/qq_34609889/article/details/86714796
https://blog.csdn.net/u014229347/article/details/93641356
下面這篇講linux下apr庫(kù)安裝
https://juejin.im/post/5b8e3d756fb9a019f82fc40d
tomcat bio nio apr 模式性能測(cè)試與個(gè)人看法
?
================
tomcat8.5以后都是NIO,可以在NIO和APR之間選
public Connector(String protocol) {boolean aprConnector = AprLifecycleListener.isAprAvailable() &&AprLifecycleListener.getUseAprConnector();if ("HTTP/1.1".equals(protocol) || protocol == null) {if (aprConnector) {protocolHandlerClassName = "org.apache.coyote.http11.Http11AprProtocol";} else {protocolHandlerClassName = "org.apache.coyote.http11.Http11NioProtocol";}} else if ("AJP/1.3".equals(protocol)) {if (aprConnector) {protocolHandlerClassName = "org.apache.coyote.ajp.AjpAprProtocol";} else {protocolHandlerClassName = "org.apache.coyote.ajp.AjpNioProtocol";}} else {protocolHandlerClassName = protocol;} 再用反射出對(duì)象
// Instantiate protocol handlerProtocolHandler p = null;try {Class<?> clazz = Class.forName(protocolHandlerClassName);p = (ProtocolHandler) clazz.getConstructor().newInstance();} catch (Exception e) {log.error(sm.getString("coyoteConnector.protocolHandlerInstantiationFailed"), e);} finally {this.protocolHandler = p;}
===========================
Spring Boot 集成undertow作為web容器
默認(rèn)是tomcat,也可以啟用undertow。
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId><exclusions><exclusion><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-tomcat</artifactId></exclusion></exclusions></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-undertow</artifactId></dependency>
?啟動(dòng)信息里面的tomcat已經(jīng)被替換為undertow:
2020-03-22 23:25:44.535 [main] [INFO ] io.undertow - starting server: Undertow - 2.0.29.Final
2020-03-22 23:25:44.542 [main] [INFO ] org.xnio - XNIO version 3.3.8.Final
2020-03-22 23:25:44.550 [main] [INFO ] org.xnio.nio - XNIO NIO Implementation Version 3.3.8.Final
2020-03-22 23:25:44.633 [main] [INFO ] o.s.b.w.embedded.undertow.UndertowServletWebServer - Undertow started on port(s) 8080 (http) with context path ''
2020-03-22 23:25:44.635 [main] [INFO ] c.p.springboot.SpringBootLearningApplication - Started SpringBootLearningApplication in 3.209 seconds (JVM running for 3.682)
?
總結(jié)
以上是生活随笔為你收集整理的Springboot源码分析之内嵌tomcat源码分析的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringBoot condition
- 下一篇: SpringBoot源码分析之@Sche