使用的成本越低,內部封裝越複雜;
一、Tomcat整合
1、依賴層級
在SpringBoot框架的web依賴包中,引入的是內嵌Tomcat元件,基於SpringBoot的版本,Tomcat整合的是9.0版本;
<!-- 1、專案工程依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<!-- 2、starter-web依賴 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<version>2.2.5.RELEASE</version>
<scope>compile</scope>
</dependency>
<!-- 3、starter-tomcat依賴 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>9.0.31</version>
<scope>compile</scope>
</dependency>
2、自動化配置
在SpringBoot框架的自動配置類中,Web專案中不顯式更換其他服務依賴時,預設提供了對Tomcat服務的管理;
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,
ServletWebServerFactoryConfiguration.EmbeddedTomcat.class})
public class ServletWebServerFactoryAutoConfiguration {
@Bean
@ConditionalOnClass(name = "org.apache.catalina.startup.Tomcat")
public TomcatServletWebServerFactoryCustomizer tomcatServletWebServerFactoryCustomizer(
ServerProperties serverProperties) {
return new TomcatServletWebServerFactoryCustomizer(serverProperties);
}
}
二、Tomcat架構
Server:代表整個Tomcat容器;
Service:伺服器內部的中間元件,將一個或多個Connector繫結到一個Engine上;
Engine:表示特定服務的請求處理管道,接收Connector的請求並響應;
Host:網路主機名稱;
Connector:聯結器處理與客戶端的通訊;
Context:代表一個Web應用程式的上下文;
參考Tomcat9.0版本的核心元件描述,對於框架有大致的瞭解後,再去分析整合原理,會更容易把握主線邏輯;
三、Tomcat配置
1、基礎配置
在配置檔案中,對Tomcat做一些基礎性的設定,檢視下面的配置類可以知道,這些屬性存在預設值;
server:
port: 8082 # 埠號
tomcat: # Tomcat元件
uri-encoding: UTF-8 # URI編碼
max-threads: 100 # 最大工作執行緒
min-spare-threads: 10 # 最小工作執行緒
2、屬性配置類
在服務配置中,提供多種伺服器的適配,像Tomcat、Jetty、Netty、Undertow,從策略上看,配置分為公共屬性以及各種伺服器的適配屬性;
更多配置資訊,可以參考完整的原始碼和註釋說明;
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {
private Integer port;
public static class Tomcat {
private Charset uriEncoding = StandardCharsets.UTF_8;
private int maxThreads = 200;
private int minSpareThreads = 10;
}
}
3、配置載入分析
- 基於配置的屬性,定製化管理Tomcat服務的資訊;
public class TomcatWebServerFactoryCustomizer
implements WebServerFactoryCustomizer<ConfigurableTomcatWebServerFactory> {
@Override
public void customize(ConfigurableTomcatWebServerFactory factory) {
ServerProperties properties = this.serverProperties;
ServerProperties.Tomcat tomcatProperties = properties.getTomcat();
PropertyMapper propertyMapper = PropertyMapper.get();
customizeStaticResources(factory);
}
}
- TomcatWeb服務工廠,這裡在建立WebServer時,使用的是Tomcat,需要適當的瞭解一下Tomcat架構;
public class TomcatServletWebServerFactory extends AbstractServletWebServerFactory
implements ConfigurableTomcatWebServerFactory, ResourceLoaderAware {
@Override
public WebServer getWebServer(ServletContextInitializer... initializers) {
Tomcat tomcat = new Tomcat();
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
tomcat.getService().addConnector(connector);
customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
configureEngine(tomcat.getEngine());
prepareContext(tomcat.getHost(), initializers);
return getTomcatWebServer(tomcat);
}
}
四、週期管理方法
1、控制類
- WebServer的簡單介面,只宣告埠獲取,服務啟動和停止相關方法;
public interface WebServer {
// 獲取監聽的埠
int getPort();
// 服務啟動
void start() throws WebServerException;
// 服務停止
void stop() throws WebServerException;
}
- SpringBoot中,Tomcat服務核心控制類,透過TomcatServletWebServerFactory工廠類建立,對Tomcat生命週期的管理提供了一層包裝;
public class TomcatWebServer implements WebServer {
private final Tomcat tomcat;
private final Map<Service, Connector[]> serviceConnectors = new HashMap<>();
}
- Apache元件中,輕量級Tomcat啟動器,提供了Tomcat基礎配置,比如預設的Port和HostName,以及生命週期管理的方法,TomcatWebServer類中呼叫的就是該API中的具體方法;
public class Tomcat {
protected Server server;
protected int port = 8080;
protected String hostname = "localhost";
// 初始化服務
public void init() throws LifecycleException {
getServer();
server.init();
}
// 啟動服務
public void start() throws LifecycleException {
getServer();
server.start();
}
// 停止服務
public void stop() throws LifecycleException {
getServer();
server.stop();
}
}
2、核心方法
2.1 初始化,初始化時,呼叫Apache-Tomcat類中啟動方法;
public class TomcatWebServer implements WebServer {
/**
* 初始化方法
*/
private void initialize() throws WebServerException {
// 控制檯日誌
logger.info("Tomcat initialized with port(s): " + getPortsDescription(false));
synchronized (this.monitor) {
// 呼叫Apache-Tomcat類中啟動方法
this.tomcat.start();
}
}
}
2.2 啟動,在初始化的方法中,呼叫的Tomcat啟動方法,這裡對狀態進行校驗並輸出日誌;
public class TomcatWebServer implements WebServer {
/**
* 啟動方法
*/
public void start() throws WebServerException {
synchronized (this.monitor) {
if (this.started) {
return;
}
checkThatConnectorsHaveStarted();
// 啟動狀態的標識
this.started = true;
// 控制檯日誌
logger.info("Tomcat started on port(s): " + getPortsDescription(true) + " with context path '"
+ getContextPath() + "'");
}
}
}
2.3 停止,在元件生命週期的常規管理邏輯中,停止服務之後進行銷燬動作的執行,其中自然涉及到多個狀態標識的轉換;
public class TomcatWebServer implements WebServer {
/**
* 停止方法
*/
public void stop() throws WebServerException {
synchronized (this.monitor) {
// 狀態變化
boolean wasStarted = this.started;
this.started = false;
// Tomcat服務停止
stopTomcat();
this.tomcat.destroy();
}
}
}
五、參考原始碼
程式設計文件:
https://gitee.com/cicadasmile/butte-java-note
應用倉庫:
https://gitee.com/cicadasmile/butte-flyer-parent