tomcat

搭建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目錄
tomcat目錄
  • 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
server
<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
StandardServer

Service(服務(wù))

一個服務(wù)組件通常包含一個引擎和與此引擎相關(guān)聯(lián)的一個或多個連接器。給服務(wù)命名可以方便管理員在日志文件中識別不同服務(wù)產(chǎn)生的日志。一個server可以包含多個service組件颁股,但通常情下只為一個server只有一個service么库。

StandardService
StandardService

Connector(連接器)

負責(zé)偵聽一個具體的TCP端口,并通過該端口處理Engine與客戶端之間的交互

Connector
Connector

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.1AJP/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"/>
示意圖
示意圖

Engine(引擎)

Engine是Service的請求處理引擎卑硫,負責(zé)處理所有Connector發(fā)過來的請求,并將內(nèi)部處理完畢的結(jié)果返回給Connector蚕断。

StandardEngine
StandardEngine

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
StandardHost

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
StandardContext

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)鍵類或接口款青。

lifecycle-hierarchy

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方法的例子辜伟。

啟動

啟動圖
啟動圖

設(shè)計模式

外觀模式

外觀模式封裝了子系統(tǒng)的具體實現(xiàn),提供統(tǒng)一的外觀類給外部系統(tǒng)狱庇,這樣當(dāng)子系統(tǒng)內(nèi)部實現(xiàn)發(fā)生變化的時候宁赤,不會影響到外部系統(tǒng)舀透。

外觀模式
外觀模式

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
enter description here

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
enter description here

每一個容器都會有一個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
enter description here

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
    enter description here
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末淋叶,一起剝皮案震驚了整個濱河市阎曹,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌煞檩,老刑警劉巖处嫌,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異斟湃,居然都是意外死亡熏迹,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門凝赛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來注暗,“玉大人坛缕,你說我怎么就攤上這事±瑁” “怎么了赚楚?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長骗卜。 經(jīng)常有香客問我直晨,道長,這世上最難降的妖魔是什么膨俐? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任勇皇,我火速辦了婚禮,結(jié)果婚禮上焚刺,老公的妹妹穿的比我還像新娘敛摘。我一直安慰自己,他們只是感情好乳愉,可當(dāng)我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布兄淫。 她就那樣靜靜地躺著,像睡著了一般蔓姚。 火紅的嫁衣襯著肌膚如雪捕虽。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天坡脐,我揣著相機與錄音泄私,去河邊找鬼。 笑死备闲,一個胖子當(dāng)著我的面吹牛晌端,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播恬砂,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼咧纠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了泻骤?” 一聲冷哼從身側(cè)響起漆羔,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎狱掂,沒想到半個月后演痒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡符欠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年嫡霞,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片希柿。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡诊沪,死狀恐怖养筒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情端姚,我是刑警寧澤晕粪,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站渐裸,受9級特大地震影響巫湘,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜昏鹃,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一尚氛、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧洞渤,春花似錦阅嘶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至护昧,卻和暖如春魂迄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背惋耙。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工捣炬, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人怠晴。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓遥金,卻偏偏與公主長得像,于是被迫代替她去往敵國和親蒜田。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內(nèi)容