Springboot源码分析之内嵌tomcat源码分析
Springboot源碼是內嵌tomcat的,這個和完整的tomcat還是不同。
內嵌tomcat的源碼在tomcat-embed-core等3個jar包里
?展開tomcat-embed-core的catalina目錄
再對照下載的apache-tomcat-9.0.31源碼
打開bin目錄,看到很多庫文件比如catalina.jar
再展開看看類文件
和之前Spring內嵌的tomcat-embed-core的catalina目錄文件一致。
所以內嵌的tomcat只用了一部分代碼。
?
內嵌tomcat的配置文件是ServerProperties.java
在org.springframework.boot.autoconfigure.web里,port等配置信息默認取這里的。
調試一下
可以看到最大線程數:maxThreads=200
最大連接數:maxConnections=8192
?
修改最大線程數和最大連接數
##端口號
server.port=8080
server.tomcat.max-threads=300
server.tomcat.max-connections=10000
已經改了
?
再看看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讀取默認的DEFAULT_PROTOCOL
啟動完成輸出日志看到確實是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相對于BIO已經是提升很多, 還可以改為更高效的APR
tomtcat7.0內置BIO,8.0,9.0都是NIO。
這三種模式的不同之處如下:
BIO:
【一個線程處理一個請求】。
缺點:【并發量高時,線程數較多,浪費資源】。
Tomcat7或以下,在Linux系統中默認使用這種方式。
NIO:
【多路復用】,可以通過【一個線程處理大量的請求】。
Tomcat8在Linux系統中默認使用這種方式。
APR:
即Apache Portable Runtime,從操作系統層面解決io阻塞問題。
Tomcat7或Tomcat8在Win7或以上的系統中啟動默認使用這種方式。
------------------------------------------------------------------------
Tomcat源碼中與connector相關的類位于org.apache.coyote包中,Connector分為以下幾類:
Http Connector, 基于HTTP協議,負責建立HTTP連接。它又分為BIO Http Connector與NIO Http Connector兩種,后者提供非阻塞IO與長連接Comet支持。默認情況下,Tomcat使用的就是這個Connector。
AJP Connector, 基于AJP協議,AJP是專門設計用來為tomcat與http服務器之間通信專門定制的協議,能提供較高的通信速度和效率。如與Apache服務器集成時,采用這個協議。
APR HTTP Connector, 用C實現,通過JNI調用的。主要提升對靜態資源(如HTML、圖片、CSS、JS等)的訪問性能。現在這個庫已獨立出來可用在任何項目中。Tomcat在配置APR之后性能非常強勁。
具體地,Tomcat7中實現了以下幾種Connector:
org.apache.coyote.http11.Http11Protocol : 支持HTTP/1.1 協議的連接器。
org.apache.coyote.http11.Http11NioProtocol : 支持HTTP/1.1 協議+New IO的連接器。
org.apache.coyote.http11.Http11AprProtocol : 使用APR(Apache portable runtime)技術的連接器,利用Native代碼與本地服務器(如linux)來提高性能。
(以上三種Connector實現都是直接處理來自客戶端Http請求,加上NIO或者APR)
org.apache.coyote.ajp.AjpProtocol:使用AJP協議的連接器,實現與web server(如Apache httpd)之間的通信
org.apache.coyote.ajp.AjpNioProtocol:SJP協議+ New IO
org.apache.coyote.ajp.AjpAprProtocol:AJP + APR
https://www.cnblogs.com/qq951785919/archive/2013/11/29/3450285.html
------------------------------------
關于? APR介紹
https://ci.apache.org/projects/tomcat/tomcat9/docs/apr.html?
介紹
Tomcat可以使用Apache Portable Runtime提供出色的可伸縮性,性能以及與本機服務器技術的更好集成。Apache可移植運行時是一個高度可移植的庫,它是Apache HTTP Server 2.x的核心。APR有許多用途,包括訪問高級IO功能(例如sendfile,epoll和OpenSSL),操作系統級別的功能(生成隨機數,系統狀態等)和本機進程處理(共享內存,NT管道和Unix套接字)。
這些功能使Tomcat成為通用的Web服務器,可以更好地與其他本機Web技術集成,并且總體上使Java作為完善的Web服務器平臺而不是僅以后端為中心的技術更加可行。
安裝
APR支持需要安裝三個主要的本機組件:
- APR庫
- Tomcat使用的APR的JNI包裝器(libtcnative)
- OpenSSL庫
APR主頁
https://apr.apache.org/
?
由于本地開發是基于Windows,Windows下需要二進制文件提供給tcnative-1,它是一個靜態編譯的.dll,其中包括OpenSSL和APR。在下載對應tomcat包,將bin目錄下的tcnative-1.dll拷貝到jdk安裝目錄的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,默認的protocol是NIO
?再set為APR
再到TomcatServletWebServerFactory.getWebServer初始化Connector
?反射出org.apache.coyote.http11.Http11AprProtocol
完成初始化
?
ServletWebServerApplicationContext.createWebServer()創建webserver 啟動完成輸出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] ?
下面這兩篇講怎么自定義配置實現自動配置
https://blog.csdn.net/qq_34609889/article/details/86714796
https://blog.csdn.net/u014229347/article/details/93641356
下面這篇講linux下apr庫安裝
https://juejin.im/post/5b8e3d756fb9a019f82fc40d
tomcat bio nio apr 模式性能測試與個人看法
?
================
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;} 再用反射出對象
// 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容器
默認是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>
?啟動信息里面的tomcat已經被替換為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)
?
總結
以上是生活随笔為你收集整理的Springboot源码分析之内嵌tomcat源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SpringBoot condition
- 下一篇: SpringBoot源码分析之@Sche