Tomcat8 的主要目錄結構
- bin 存放可執行文件
- conf 存放配置文件
- lib 存放Tomcat運行需要的包
- logs 存放運行的日誌
- webapps 存放默認的web應用部署目錄
- work 存放web應用代碼生成和編譯文件的臨時目錄
組件結構
- connector,負責接收和反饋外部請求的連接器
- container,負責處理請求的容器
- service,由connecter和container一起構成,Tomcat可以管理多個service,每個service之間相互獨立
連接器
- 核心功能
1,監聽網絡端口,接收和相應網絡請求。
2,網絡字節流處理,將收到的網絡字節流轉換成TomcatRequest再轉成標準的ServletRequest給容器。
同時將容器傳回來的ServletResponse轉爲TomcatResponse再轉成網絡字節流。
- 模塊設計
1,EndPointer,端點,用來處理Socket接收和發送的邏輯,內部由Acceptor監聽請求,Handler處理數據,AsyncTimeout檢查請求超時,具體實現有NioEndPoint,AprEndPointer。
2,Processor,處理器,負責構建TomcatRequest和TomcatResponse對象,具體的實現是Http11Processor,StreamProcessor等等。
3,Adapter,適配器,實現TomcatRequest和ServletRequest的互相轉換,採用了經典的適配器模式。
4,ProtocolHandler,協議處理器,將不同協議和通訊方式組合封裝成對應的協議處理器。
容器
- 容器結構
每個Service會包含一個容器,容易有一個引擎,可以管理多個虛擬主機,每個虛擬主機可以管理多個web應用,每個web應用會有多個Servlet包裝器,
1,Engine,引擎,可以管理多個虛擬主機
2,Host,虛擬主機,負責多個應用的部署
3,Context,web應用,包含多個Servlet封裝器
4,Wrapper,封裝器,容器的最底層,對Servlet進行封裝,負責實例的創建,執行和銷燬。
這四個按順序爲父子關係。
容器請求處理
容器的請求處理過程就是上面所提到的四個容器之間的層層調用,最後在Servlet中執行相應的業務邏輯,各個容器都會有一個通道pipeline,每個通道上都會有一個BasicValue,類似於一個閘門,用來處理Request和Response。
映射器
映射器,將請求url的地址匹配由哪個容器來處理,其中每個容器都有自己實現自己的映射器。
淺析Tomcat處理一個http請求的流程
以http://localhost:8080/docs/api爲例
1,連接器監聽的端口是8080,連接器接收該請求。
2,引擎的默認虛擬主機是localhost,並且虛擬主機的目錄是webapps,所以請求找到tomcat/webapps目錄
3,解析docs是web程序的應用名,也就是context上下文,此時請求繼續從webapps目錄下找到docs目錄。
4,解析的api是具體的業務邏輯地址,此時需要從docs/WEB-INF/web.xml中找到映射關係,最後調用具體的函數。
Springboot啓動內嵌Tomcat的過程
說實話,一直在用Springboot,確實還沒了解過內嵌Tomcat的使用方法。中小型項目雖然可以直接內嵌Tomcat啓動,但是遇到大型項目,需要用到Tomcat集羣,並且需要調優,那可能就不能滿足了。
從SpringBoot main函數開始看
SpringAppliation.run();
public void refresh() throws BeansException, IllegalStateException {
Object var1 = this.startupShutdownMonitor;
synchronized(this.startupShutdownMonitor) {
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var9) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var9);
}
this.destroyBeans();
this.cancelRefresh(var9);
throw var9;
} finally {
this.resetCommonCaches();
}
}
}
繼續往裏面看就是上面這個refresh方法,然後在看到這裏的onRefresh方法,熟悉的肯定這個名字就是典型的模板方法,那繼續看下去。在ServletWebServerApplicationContxt再看onRefresh()
protected void onRefresh() {
super.onRefresh();
try {
this.createWebServer();
} catch (Throwable var2) {
throw new ApplicationContextException("Unable to start web server", var2);
}
}
這裏就會創建WebServer了,再看這裏頭做了什麼。
private void createWebServer() {
WebServer webServer = this.webServer;
ServletContext servletContext = this.getServletContext();
if (webServer == null && servletContext == null) {
ServletWebServerFactory factory = this.getWebServerFactory();
this.webServer = factory.getWebServer(new ServletContextInitializer[]{this.getSelfInitializer()});
this.getBeanFactory().registerSingleton("webServerGracefulShutdown", new WebServerGracefulShutdownLifecycle(this.webServer));
this.getBeanFactory().registerSingleton("webServerStartStop", new WebServerStartStopLifecycle(this, this.webServer));
} else if (servletContext != null) {
try {
this.getSelfInitializer().onStartup(servletContext);
} catch (ServletException var4) {
throw new ApplicationContextException("Cannot initialize servlet context", var4);
}
}
this.initPropertySources();
}
看到getWebServerFactory,去找對應的實現方法。在TomcatServletWebServerFactory裏找到對應的方法。
public WebServer getWebServer(ServletContextInitializer... initializers) {
if (this.disableMBeanRegistry) {
Registry.disableRegistry();
}
Tomcat tomcat = new Tomcat();
File baseDir = this.baseDirectory != null ? this.baseDirectory : this.createTempDir("tomcat");
tomcat.setBaseDir(baseDir.getAbsolutePath());
Connector connector = new Connector(this.protocol);
connector.setThrowOnFailure(true);
tomcat.getService().addConnector(connector);
this.customizeConnector(connector);
tomcat.setConnector(connector);
tomcat.getHost().setAutoDeploy(false);
this.configureEngine(tomcat.getEngine());
Iterator var5 = this.additionalTomcatConnectors.iterator();
while(var5.hasNext()) {
Connector additionalConnector = (Connector)var5.next();
tomcat.getService().addConnector(additionalConnector);
}
this.prepareContext(tomcat.getHost(), initializers);
return this.getTomcatWebServer(tomcat);
}
這裏終於可以看到和之前整理的Tomcat結構相關的東西了,在這裏配置了基本的連接器,引擎和虛擬站點。