搭建Tomcat源碼項目
下載tomcat源代碼 下載地址
-
編寫一個pom.xml 文件,給Tomcat使用揽咕。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.apache.tomcat</groupId> <artifactId>Tomcat8.0</artifactId> <name>Tomcat8.0</name> <version>8.0</version> <build> <finalName>Tomcat8.0</finalName> <sourceDirectory>java</sourceDirectory> <testSourceDirectory>test</testSourceDirectory> <resources> <resource> <directory>java</directory> </resource> </resources> <testResources> <testResource> <directory>test</directory> </testResource> </testResources> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>2.3</version> <configuration> <encoding>UTF-8</encoding> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.easymock</groupId> <artifactId>easymock</artifactId> <version>3.4</version> </dependency> <dependency> <groupId>ant</groupId> <artifactId>ant</artifactId> <version>1.7.0</version> </dependency> <dependency> <groupId>wsdl4j</groupId> <artifactId>wsdl4j</artifactId> <version>1.6.2</version> </dependency> <dependency> <groupId>javax.xml</groupId> <artifactId>jaxrpc</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>org.eclipse.jdt.core.compiler</groupId> <artifactId>ecj</artifactId> <version>4.5.1</version> </dependency> </dependencies> </project>
-
在idea中導(dǎo)入Tomcat工程后拷橘,需要給Bootstrap運行時的CATALINA_HOME目錄途戒,在Tomcat項目的平級目錄下建一個catalina-home目錄愈魏,這時需要下載一個Binary 包搭综,解壓后把一些文件拷貝到catalina-home目錄中。
bin
conf
lib
logs
temp
webapps
work -
配置Bootstrap運行環(huán)境
在Man class:中填入栖忠,org.apache.catalina.startup.Bootstrap
在VM options:中填入設(shè)置catalina-home路徑,我的路徑是-Dcatalina.home="E:\tomcat\catalina-home"
這是啟動時崔挖,會報一些架包不存在錯誤贸街,可以先刪除test路徑的配置
工程目錄
![tomcat目錄](https://www.github.com/COBSNAN/ImageHub/raw/master/1517640277301.jpg)
- javax:Java中標準的Servlet規(guī)范庵寞。
- catalina:Tomcat中的Servlet容器。
- coyote:Tomcat中的連接器薛匪。
- el:正則表達式解析規(guī)范捐川。
- jasper:JSP文件解析規(guī)范。
- juli:Tomcat的日志系統(tǒng)逸尖。
- naming:JNDI的實現(xiàn)古沥。
- tomcat:Tomcat的工具包瘸右。
Tomcat中三種部署項目的方法
- 在tomcat中的conf目錄中,在server.xml中<host/>節(jié)點下添加Context節(jié)點
- 將web項目文件件拷貝到webapps 目錄中
- 在conf\Catalina\localhost目錄下建一個文件岩齿,文件名和項目名一致太颤,主要是在安全模式下部署
配置文件
- server.xml: Tomcat的主配置文件,包含Service, Connector, Engine, Realm, Valve, Hosts主組件的相關(guān)配置信息盹沈;
- web.xml:遵循Servlet規(guī)范標準的配置文件龄章,用于配置servlet,并為所有的Web應(yīng)用程序提供包括MIME映射等默認配置信息乞封;
- tomcat-user.xml:Realm認證時用到的相關(guān)角色做裙、用戶和密碼等信息;Tomcat自帶的manager默認情況下會用到此文件肃晚;
- catalina.policy:Java相關(guān)的安全策略配置文件锚贱,在系統(tǒng)資源級別上提供訪問控制的能力;
- catalina.properties:Tomcat內(nèi)部package的定義及訪問相關(guān)的控制关串,也包括對通過類裝載器裝載的內(nèi)容的控制拧廊;
- logging.properties: Tomcat內(nèi)部實現(xiàn)的JAVA日志記錄器來記錄操作相關(guān)的日志,此文件即為日志記錄器相關(guān)的配置信息晋修,可以用來定義日志記錄的組件級別以及日志文件的存在位置等卦绣;
- context.xml:所有host的默認配置信息;
catalina.policy文件
標準權(quán)限
- java.util.PropertyPermission——控制對 JVM 屬性的讀/寫飞蚓,比如說 java.home滤港。
- java.lang.RuntimePermission——控制一些系統(tǒng)/運行時函數(shù)的使用,比如 exit() 和 exec()趴拧。 另外也控制包的訪問/定義。
- java.io.FilePermission——控制對文件和目錄的讀/寫/執(zhí)行。
- java.net.SocketPermission——控制網(wǎng)絡(luò)套接字的使用问麸。
- java.net.NetPermission——控制組播網(wǎng)絡(luò)連接的使用哮笆。
- java.lang.reflect.ReflectPermission——控制類反射的使用萝毛。
- java.security.SecurityPermission——控制對 Security 方法的訪問色查。
- java.security.AllPermission——允許訪問任何權(quán)限,仿佛沒有 SecurityManager哟玷。-
// 策略文件項范例
grant [signedBy <signer>,] [codeBase <code source>] {
permission <class> [<name> [, <action list>]];
};
- codeBase 是通過URL的方式指定文件抑月,可以使用變量java.home或者java.home或者{catalina.home}來表示JDK和tomcat的根目錄性锭。
- class 指定了相應(yīng)的權(quán)限類型
- [name,[,action]] name指定具體的操作或者文件,action指定可選的動作(比如read write等等)
進入安全模式
$CATALINA_HOME/bin/catalina.sh start -security (Unix)
%CATALINA_HOME%\bin\catalina start -security (Windows)
啟動安全模式后你踩,這時manage 項目起不起來式廷,需要通過虛擬主機目錄配置context.xml 文件才能啟動辛馆。
<Context docBase="${catalina.home}/webapps/manager" path="/manager"
privileged="true" antiResourceLocking="false" antiJARLocking="false">
</Context>
grant {
permission java.io.FilePermission "E:/testfile/nio-data.txt", "read";
permission java.util.PropertyPermission "file.encoding", "read";
};
import="java.net.*,java.io.*"
<%
System.out.println("SecurityManager: " + System.getSecurityManager());
String result = "";
try{
File file = new File("E:\\testfile\\nio-data.txt");
BufferedReader br = new BufferedReader(new FileReader(file));
String s = null;
while((s = br.readLine())!=null){
result = result + "\n" +s;
}
br.close();
}catch(Exception e){
e.printStackTrace();
}
System.out.println(result);
System.out.println(System.getProperty("file.encoding"));
%>
logging.properties 文件
日志輸出級別:SEVERE (最高級別) > WARNING > INFO > CONFIG > FINE > FINER > FINEST (所有內(nèi)容,最低級別)
禁用日志的輸出設(shè)置為OFF, 輸出所有的日志消息設(shè)置為ALL
org.apache.catalina.core.ContainerBase.[Catalina].[localhost].[/host-manager].handlers = 4host-manager.org.apache.juli.AsyncFileHandler
其中Catalina表示Engine 名,localhost表示Host 名昙篙,/host-manager 這個是請求路徑
web.xml文件
JspServlet
- checkInterval 多長時間監(jiān)測jsp文件是否修改倔韭,進行重新加載
- javaEncoding java文件編碼格式
- maxLoadedJsps 應(yīng)用程序最大加載jsp文件數(shù),默認-1 沒有限制瓢对。超過數(shù)量按最近未使用過jsp進行卸載
- jspIdleTimeout 多長時間未使用就卸載jsp寿酌。
server.xml文件
![server](https://www.github.com/COBSNAN/ImageHub/raw/master/1517732159336.jpg)
<Server> <!-- 頂級元素 -->
<Listener/> <!-- 組件 -->
<GlobalNamingResources/> <!-- 組件 -->
<Service> <!-- 另一個頂級元素 -->
<Connector/> <!-- 接頭 -->
<Engine> <!-- 容器 -->
<Realm/> <!-- 組件 -->
<Host> <!-- 容器 -->
<Valve/> <!-- 組件 -->
<Context></Context> <!-- 容器 -->
</Host>
</Engine>
</Service>
</Server>
Server(服務(wù)器)
Tomcat的一個實例,通常一個JVM只能包含一個Tomcat實例硕蛹;因此醇疼,一臺物理服務(wù)器上可以在啟動多個JVM的情況下在每一個JVM中啟動一個Tomcat實例,每個實例分屬于一個獨立的管理端口法焰。
Server有兩種特有的組件秧荆,一個是GlobalNamingResources(全局命名資源),一個是Listener(監(jiān)聽器)可以作用于不同層次容器的組件埃仪。除此之外乙濒,還有Service(服務(wù))
![StandardServer](https://www.github.com/COBSNAN/ImageHub/raw/master/StandardServer.png)
Service(服務(wù))
一個服務(wù)組件通常包含一個引擎和與此引擎相關(guān)聯(lián)的一個或多個連接器。給服務(wù)命名可以方便管理員在日志文件中識別不同服務(wù)產(chǎn)生的日志。一個server可以包含多個service組件颁股,但通常情下只為一個server只有一個service么库。
![StandardService](https://www.github.com/COBSNAN/ImageHub/raw/master/StandardService.png)
Connector(連接器)
負責(zé)偵聽一個具體的TCP端口,并通過該端口處理Engine與客戶端之間的交互
![Connector](https://www.github.com/COBSNAN/ImageHub/raw/master/Connector.png)
Connector屬性
- address:指定連接器監(jiān)聽的地址甘有,默認為所有地址诉儒,即0.0.0.0;
- maxThreads:支持的最大并發(fā)連接數(shù)亏掀,默認為200忱反;
- port:監(jiān)聽的端口,默認為0滤愕;
- redirectPort:如果某連接器支持的協(xié)議是HTTP温算,當(dāng)接收客戶端發(fā)來的HTTPS請求時,則轉(zhuǎn)發(fā)至此屬性定義的端口间影;
- connectionTimeout:等待客戶端發(fā)送請求的超時時間米者,單位為毫秒,默認為60000宇智,即1分鐘蔓搞;
- enableLookups:是否通過request.getRemoteHost()進行DNS查詢以獲取客戶端的主機名;默認為true随橘;
- acceptCount:設(shè)置等待隊列的最大長度喂分;通常在tomcat所有處理線程均處于繁忙狀態(tài)時,新發(fā)來的請求將被放置于等待隊列中机蔗;
- URIEncoding:指定對所有GET方式請求進行統(tǒng)一的重新編碼(解碼)的編碼
- useBodyEncodingForURI:是否用request.setCharacterEncoding參數(shù)對URL提交的數(shù)據(jù)和表單中GET方式提交的數(shù)據(jù)進行重新編碼蒲祈,在默認情況下,該參數(shù)為false
- protocol:連接器使用的協(xié)議萝嘁,默認為HTTP/1.1梆掸,定義AJP協(xié)議時通常為AJP/1.3;
有兩種協(xié)議HTTP/1.1
和AJP/1.3
兩種協(xié)議
HTTP是主要是否則接受來自客戶端的請求牙言,AJP主要是和一個web容器進行交互酸钦,比如Apache服務(wù)器,目的在于靜態(tài)資源和動態(tài)資源分離咱枉。
//生產(chǎn)
keytool -genkeypair -alias "tomcat" -keyalg "RSA" -keystore "d:\ssl\tomcat.keystore"
<Connector
protocol="org.apache.coyote.http11.Http11NioProtocol"
port="8443" maxThreads="200"
scheme="https" secure="true" SSLEnabled="true"
keystoreFile="E:\tomcat\catalina-home\conf\tomcat.keystore" keystorePass="123456"
clientAuth="false" sslProtocol="TLS"/>
![示意圖](https://www.github.com/COBSNAN/ImageHub/raw/master/1517743979552.jpg)
Engine(引擎)
Engine是Service的請求處理引擎卑硫,負責(zé)處理所有Connector發(fā)過來的請求,并將內(nèi)部處理完畢的結(jié)果返回給Connector蚕断。
![StandardEngine](https://www.github.com/COBSNAN/ImageHub/raw/master/StandardEngine.png)
Engine元素屬性
- Engine.name - 引擎的名稱
- Engine.defaultHost - 默認采用哪一個子容器Host來處理請求
- Engine.jvmRoute - 一個用于負載均衡場景下的唯一標識符
- 默認的負載均衡場景下欢伏,Tomcat采用一種被稱作粘性session的機制管理session信息。
Realm
用于用戶的認證和授權(quán)亿乳;在配置一個應(yīng)用程序時硝拧,管理員可以為每個資源或資源組定義角色及權(quán)限,而這些訪問控制功能的生效需要通過Realm來實現(xiàn)。Realm的認證可以基于文本文件障陶、數(shù)據(jù)庫表滋恬、LDAP服務(wù)等來實現(xiàn)。Realm的效用會遍及整個引擎或頂級容器咸这,因此夷恍,一個容器內(nèi)的所有應(yīng)用程序?qū)⒐蚕碛脩糍Y源魔眨。同時媳维,Realm可以被其所在組件的子組件繼承,也可以被子組件中定義的Realm所覆蓋遏暴。
- JDBCRealm 用戶授權(quán)信息存儲于某個關(guān)系型數(shù)據(jù)庫中侄刽,通過JDBC驅(qū)動獲取信息驗證
- DataSourceRealm 用戶授權(quán)信息存儲于關(guān)于型數(shù)據(jù)中,通過JNDI配置JDBC數(shù)據(jù)源的方式獲取信息驗證
- JNDIRealm 用戶授權(quán)信息存儲在基于LDAP的目錄服務(wù)的服務(wù)器中朋凉,通過JNDI驅(qū)動獲取并驗證
- UserDatabaseRealm 默認的配置方式州丹,信息存儲于XML文檔中 conf/tomcat-users.xml
- MemoryRealm 用戶信息存儲于內(nèi)存的集合中,對象集合的數(shù)據(jù)來源于xml文檔 conf/tomcat-users.xml
- JAASRealm 通過JAAS框架訪問授權(quán)信息
Host(主機)
![StandardHost](https://www.github.com/COBSNAN/ImageHub/raw/master/StandardHost.png)
Host元素屬性
- appBase:存放非歸檔的web應(yīng)用程序的目錄或歸檔后的WAR文件的目錄路徑杂彭;可以使用基于$CATALINA_HOME的相對路徑墓毒;
- autoDeploy:在Tomcat處于運行狀態(tài)時放置于appBase目錄中的應(yīng)用程序文件是否自動進行deploy;默認為true亲怠;
- unpackWars:在啟用此webapps時是否對WAR格式的歸檔文件先進行展開所计;默認為true;
- xmlBase:虛擬主機目錄团秽。 如果沒有指定默認的conf/<engine_name>/<host_name>
- deployXML:是否部署項目下Context.xml 文件(位于/META-INF/context.xml)主胧。安全模式下設(shè)置為false
Context(上下文)
Context組件是最內(nèi)層次的組件,它表示W(wǎng)eb應(yīng)用程序本身习勤。配置一個Context最主要的是指定Web應(yīng)用程序的根目錄踪栋,以便Servlet容器能夠?qū)⒂脩粽埱蟀l(fā)往正確的位置。
![StandardContext](https://www.github.com/COBSNAN/ImageHub/raw/master/StandardContext.png)
Context元素屬性
- docBase:應(yīng)用程序的路徑或者是WAR文件存放的路徑
- path:此web應(yīng)用程序的上下文路徑
- reloadable:是否支持熱部署
Valve(閥門)
Valve的中文含義是閥門图毕,可以簡單地理解為Tomcat的攔截器夷都。它負責(zé)在請求發(fā)送到應(yīng)用之前攔截HTTP請求,可以定義在任何容器中予颤。默認配置中定義了一個AccessLogValve损肛,負責(zé)攔截HTTP請求,并寫入到日志文件中荣瑟。
Listener(監(jiān)聽組件)
- AprLifecycleListener 檢測apr模式是否支持治拿。useAprConnector 這個屬性來表示是否開啟apr模式
- GlobalResourcesLifecycleListener 作用于全局資源,保證 JNDI 對資源的可達性笆焰,比如數(shù)據(jù)庫
- VersionLoggerListener 監(jiān)聽tomcat啟動日志信息 logProps屬性表示是否打印系統(tǒng)屬性
生命周期
每一個組件都會存在很多的狀態(tài)劫谅,如初始化、開始、停止等等捏检。而在狀態(tài)之間的切換需要做很多相應(yīng)的工作荞驴。我們把Tomcat組件的各個狀態(tài)以及狀態(tài)之間的轉(zhuǎn)換統(tǒng)稱為Tomcat的生命周期。在Tomcat中參與生命周期管理的主要有以下幾個類或接口:
- Lifecycle:表示生命周期概念的接口贯城。
- LifecycleListener:用來監(jiān)聽組件狀態(tài)變化并觸發(fā)相應(yīng)事件的監(jiān)聽器熊楼。
- LifecycleEvent:組件狀態(tài)變化時觸發(fā)的事件。
- LifecycleException:生命周期相關(guān)異常能犯。
- LifecycleState:組件的有效狀態(tài)枚舉鲫骗。
- LifecycleSupport:用來幫助傳送消息給監(jiān)聽器的輔助類。
- LifecycleBase:Lifecycle接口的基礎(chǔ)實現(xiàn)類踩晶,主要實現(xiàn)了制定啟動和停止狀態(tài)相關(guān)的轉(zhuǎn)換規(guī)則执泰。
Lifecycle
這個接口聲明了能對組件施加影響的生命周期事件類型常量,可以分為在狀態(tài)中渡蜻、狀態(tài)前和狀態(tài)后(不是每個狀態(tài)都有這相應(yīng)的三種情況)术吝。包含的狀態(tài)有初始化、啟動茸苇、停止排苍、銷毀、配置学密,以及一個特殊的階段性狀態(tài)淘衙,具體常量如下:
public static final String BEFORE_INIT_EVENT = "before_init";
public static final String AFTER_INIT_EVENT = "after_init";
public static final String START_EVENT = "start";
public static final String BEFORE_START_EVENT = "before_start";
public static final String AFTER_START_EVENT = "after_start";
public static final String STOP_EVENT = "stop";
public static final String BEFORE_STOP_EVENT = "before_stop";
public static final String AFTER_STOP_EVENT = "after_stop";
public static final String AFTER_DESTROY_EVENT = "after_destroy";
public static final String BEFORE_DESTROY_EVENT = "before_destroy";
public static final String PERIODIC_EVENT = "periodic";
public static final String CONFIGURE_START_EVENT = "configure_start";
public static final String CONFIGURE_STOP_EVENT = "configure_stop";
Lifecycle對外提供的方法主要分為兩大類,一類是對監(jiān)聽器的管理则果,另一類是生命周期的各個狀態(tài)幔翰,需要根據(jù)狀態(tài)來做相應(yīng)動作和觸發(fā)事件。
//監(jiān)聽器的添加西壮、查找與刪除操作
public void addLifecycleListener(LifecycleListener listener);
public LifecycleListener[] findLifecycleListeners();
public void removeLifecycleListener(LifecycleListener listener);
//觸發(fā)各個狀態(tài)相關(guān)的生命周期事件來進行準備和善后處理
public void init() throws LifecycleException;
public void start() throws LifecycleException;
public void stop() throws LifecycleException;
public void destroy() throws LifecycleException;
//獲取組件當(dāng)前狀態(tài)
public LifecycleState getState();
public String getStateName();
實現(xiàn)了Lifecycle接口的非常之多遗增,具體可以去看它繼承樹,這里給出一些實現(xiàn)或繼承該接口的關(guān)鍵類或接口款青。
LifecycleListener
LifecycleListener表示對某一個生命周期事件的監(jiān)聽做修。這個接口非常簡單,只有一個方法抡草。
//定義某一事件發(fā)生時需要的行為
public void lifecycleEvent(LifecycleEvent event);
LifecycleEvent
LifecycleEvent繼承自Java的事件對象EventObject饰及,是一個簡單的類,由事件相關(guān)組件康震、事件的類型和事件相關(guān)數(shù)據(jù)組成燎含。
public final class LifecycleEvent extends EventObject {
private static final long serialVersionUID = 1L;
private final Object data;
private final String type;
public LifecycleEvent(Lifecycle lifecycle, String type, Object data) {
super(lifecycle);
this.type = type;
this.data = data;
}
public Object getData() {
return (this.data);
}
public Lifecycle getLifecycle() {
return (Lifecycle) getSource();
}
public String getType() {
return (this.type);
}
}
LifecycleException
LifecycleException表示一個生命周期相關(guān)的異常,繼承自Java的Exception類腿短,提供了多種不同的構(gòu)造函數(shù)屏箍,此外不能自定義它的子類绘梦。
public final class LifecycleException extends Exception {
private static final long serialVersionUID = 1L;
public LifecycleException() {
super();
}
public LifecycleException(String message) {
super(message);
}
public LifecycleException(Throwable throwable) {
super(throwable);
}
public LifecycleException(String message, Throwable throwable) {
super(message, throwable);
}
}
LifecycleState
LifecycleState枚舉出了一個組件合法的生命周期狀態(tài),并對外提供兩個參數(shù)赴魁,一個是獲取生命周期事件卸奉,即在該狀態(tài)下應(yīng)該調(diào)用哪類生命周期事件,另一個是在該狀態(tài)下能否調(diào)用組件除了getter/setter和生命周期方法外的其他public方法颖御。
public enum LifecycleState {
NEW(false, null),
INITIALIZING(false, Lifecycle.BEFORE_INIT_EVENT),
INITIALIZED(false, Lifecycle.AFTER_INIT_EVENT),
STARTING_PREP(false, Lifecycle.BEFORE_START_EVENT),
STARTING(true, Lifecycle.START_EVENT),
STARTED(true, Lifecycle.AFTER_START_EVENT),
STOPPING_PREP(true, Lifecycle.BEFORE_STOP_EVENT),
STOPPING(false, Lifecycle.STOP_EVENT),
STOPPED(false, Lifecycle.AFTER_STOP_EVENT),
DESTROYING(false, Lifecycle.BEFORE_DESTROY_EVENT),
DESTROYED(false, Lifecycle.AFTER_DESTROY_EVENT),
FAILED(false, null),
MUST_STOP(true, null),
MUST_DESTROY(false, null);
private final boolean available;
private final String lifecycleEvent;
private LifecycleState(boolean available, String lifecycleEvent) {
this.available = available;
this.lifecycleEvent = lifecycleEvent;
}
//能否調(diào)用其他公共分方法
public boolean isAvailable() {
return available;
}
public String getLifecycleEvent() {
return lifecycleEvent;
}
}
LifecycleSupport
LifecycleSupport是用來將事件通知給一個組件的所有監(jiān)聽器的輔助類榄棵。它包含了組件和該組件所有的監(jiān)聽器。其中監(jiān)聽器用了線程安全的CopyOnWriteArrayList來存儲潘拱,主要的事件通知函數(shù)如下:
public void fireLifecycleEvent(String type, Object data) {
LifecycleEvent event = new LifecycleEvent(lifecycle, type, data);
for (LifecycleListener listener : listeners) {
listener.lifecycleEvent(event);
}
}
LifecycleBase
LifecycleBase是實現(xiàn)了Lifecycle的抽象類疹鳄。它通過持有一個LifecycleSupport來管理監(jiān)聽器。具體的狀態(tài)函數(shù)使用了模板方法模式泽铛,LifecycleBase規(guī)定了個狀態(tài)之間的轉(zhuǎn)換規(guī)則(是否合法以及狀態(tài)間的自動轉(zhuǎn)換等尚辑,具體參看LifecycleState中的狀態(tài)轉(zhuǎn)換圖)辑鲤,而讓用戶繼承的子類來實現(xiàn)具體的操作盔腔。由于代碼較多润樱,舉一個start方法的例子辜伟。
啟動
![啟動圖](https://www.github.com/COBSNAN/ImageHub/raw/master/1517789479176.jpg)
設(shè)計模式
外觀模式
外觀模式封裝了子系統(tǒng)的具體實現(xiàn),提供統(tǒng)一的外觀類給外部系統(tǒng)狱庇,這樣當(dāng)子系統(tǒng)內(nèi)部實現(xiàn)發(fā)生變化的時候宁赤,不會影響到外部系統(tǒng)舀透。
![外觀模式](https://www.github.com/COBSNAN/ImageHub/raw/master/1517876786509.jpg)
RequestFacade包裝了Request,它們都實現(xiàn)了HttpServletRequest决左,當(dāng)傳遞Request對象給應(yīng)用的時候愕够,其實是返回了RequestFacade對象,而RequestFacade內(nèi)部可以根據(jù)是否自定義了安全管理器來進行相應(yīng)的操作佛猛。
觀察者模式
觀察者模式是一種非常常用的模式惑芭,比如大家熟悉的發(fā)布-訂閱模式,客戶端應(yīng)用中的事件監(jiān)聽器继找,以及通知等其實都屬于觀察者模式遂跟。觀察者模式主要是在當(dāng)系統(tǒng)中發(fā)生某個狀態(tài)變更或者事件的時候,有另外一些組件或者對象對此次變化有興趣婴渡,這個時候那些對變化感興趣的對象就可以做為觀察者對象來監(jiān)聽變化幻锁,而被觀察對象要負責(zé)發(fā)生變化的時候觸發(fā)通知操作。
![enter description here](https://www.github.com/COBSNAN/ImageHub/raw/master/1517877074256.jpg)
Tomcat抽象了一個LifecycleSupport的類边臼,而所有需要生命周期管理的組件通過LifecycleSupport類通知對某個生命周期事件感興趣的觀察者哄尔,而所有的觀察者都需要實現(xiàn)LifecycleListener。
責(zé)任鏈模式
通過名稱我們應(yīng)該就能知道責(zé)任鏈模式是解決啥問題的柠并?當(dāng)我們系統(tǒng)在處理某個請求的時候岭接,請求需要經(jīng)過很多個節(jié)點進行處理置谦,每個節(jié)點只關(guān)注自己的應(yīng)該做的工作,做完自己的工作以后亿傅,將工作轉(zhuǎn)給下一個節(jié)點進行處理媒峡,直到所有節(jié)點都處理完畢。責(zé)任鏈模式在日常生活中例子挺多葵擎,比如快遞谅阿,當(dāng)你發(fā)一個從深圳到北京的快遞的時候,你的包裹會從一個分撥中心傳遞到下一個分撥中心酬滤,直到目的地签餐,這里面每個分撥中心都是鏈路上的一個節(jié)點,它做完自己的工作盯串,然后將工作傳遞到下一個節(jié)點氯檐,還比如路由器中傳遞某個數(shù)據(jù)包其實也是同樣的思路。
![enter description here](https://www.github.com/COBSNAN/ImageHub/raw/master/1517877159404.jpg)
每一個容器都會有一個Pipeline体捏,而一個Pipeline又會具有多個Valve閥門冠摄,其中StandardEngine對應(yīng)的閥門是StandardEngineValve,StandardHost對應(yīng)的閥門是StandardHostValve几缭,StandardContext對應(yīng)的閥門是StandardContextValve河泳,StandardWrapper對應(yīng)的閥門是StandardWrapperValve。這里每一Pipeline就好比一個管道年栓,而每一Valve就相當(dāng)于一個閥門拆挥,一個管道可以有多個閥門,而對于閥門來說有兩種某抓,一種閥門在處理完自己的事情以后纸兔,只需要將工作委托給下一個和自己在同一管道的閥門即可,第二種閥門是負責(zé)銜接各個管道的否副,它負責(zé)將請求傳遞給下個管道的第一個閥門處理汉矿,而這種閥門叫Basic閥門,它是每個管道中最后一個閥門副编,上面的StandardValve都屬于第二種閥門负甸。
模板方法模式
模板方法模式抽象出某個業(yè)務(wù)操作公共的流程,將流程分為幾個步驟痹届,其中有一些步驟是固定不變的呻待,有一些步驟是變化的,固定不變的步驟通過一個基類來實現(xiàn)队腐,而變化的部分通過鉤子方法讓子類去實現(xiàn)蚕捉,這樣就實現(xiàn)了對系統(tǒng)中流程的統(tǒng)一化規(guī)范化管理。在日常生活中其實也有類似的例子柴淘,比如我們知道的連鎖加盟店迫淹,他們都是有固定的加盟流程秘通,只不過每一家店開的時候,店的選址敛熬,裝修等不同的而已肺稀,但是總體的加盟流程已經(jīng)是確定的。
![enter description here](https://www.github.com/COBSNAN/ImageHub/raw/master/1517877278817.jpg)
Tomcat中關(guān)于生命周期管理的地方很好應(yīng)用了模板方法模式应民,在一個組件的生命周期中都會涉及到init(初始化)话原,start(啟動),stop(停止)诲锹,destory(銷毀)繁仁,而對于每一個生命周期階段其實都有固定一些事情要做,比如判斷前置狀態(tài)归园,設(shè)置后置狀態(tài)黄虱,以及通知狀態(tài)變更事件的監(jiān)聽者等,而這些工作其實是可以固化的庸诱,所以Tomcat中就將每個生命周期階段公共的部分固化捻浦,然后通過initInternal,startInternal,stopInternal,destoryInternal這幾個鉤子方法開放給子類去實現(xiàn)具體的邏輯.
Connector的三種運行模式
- BIO : 一個線程處理一個請求。缺點:并發(fā)量高時偶翅,線程數(shù)較多默勾,浪費資源碉渡。Tomcat7或以下聚谁,在Linux系統(tǒng)中默認使用這種方式。
- NIO:利用Java的異步IO處理滞诺,可以通過少量的線程處理大量的請求形导。Tomcat8默認使用這種方式。
-
APR :即Apache Portable Runtime习霹,從操作系統(tǒng)層面解決io阻塞問題朵耕。Tomcat8在Win7或以上的系統(tǒng)中可以這種方式。而在linux系統(tǒng)中需要額為安裝APR庫和OpenSSL相關(guān)庫
enter description here