Tomcat是一個JSP/Servlet容器。其做爲Servlet容器,有三種工做模式:獨立的Servlet容器、進程內的Servlet容器和進程外的Servlet容器。html
Tomcat是一個基於組件的服務器,它的構成組件都是可配置的,其中最外層的是Catalina servlet容器,其餘組件按照必定的格式要求配置在這個頂層容器中。
Tomcat的各類組件都是在Tomcat安裝目錄下的/conf/server.xml文件中配置的。前端
Tomcat目錄java
tomcat
|---bin:存放啓動和關閉tomcat腳本mysql
|---conf:存放不一樣的配置文件(server.xml和web.xml);
|---doc:存放Tomcat文檔;
|---lib/japser/common:存放Tomcat運行須要的庫文件(JARS);
|---logs:存放Tomcat執行時的LOG文件;
|---src:存放Tomcat的源代碼;
|---webapps:Tomcat的主要Web發佈目錄(包括應用程序示例);
|---work:存放jsp編譯後產生的class文件;web
TomCat配置文件sql
Tomcat架構及經常使用的組件:數據庫
一、Server組件express
如上面示例文件中定義的:apache
<Server port=」8005」 shutdown=」SHUTDOWN」>設計模式
這會讓Tomcat6啓動一個server實例(即一個JVM),它監聽在8005端口以接收shutdown命令,使用 telnet 鏈接8005 端口能夠直接執行 SHUTDOWN 命令來關閉 Tomcat。各Server的定義不能使用同一個端口,這意味着若是在同一個物理機上啓動了多個Server實例,必須配置它們使用不一樣的端口。這個端口的定義用於爲管理員提供一個關閉此實例的便捷途徑,所以,管理員能夠直接telnet至此端口使用SHUTDOWN命令關閉此實例。不過,基於安全角度的考慮,這一般不容許遠程進行。
Server的相關屬性:
className: 用於實現此Server容器的徹底限定類的名稱,默認爲org.apache.catalina.core.StandardServer;
port: 接收shutdown指令的端口,默認僅容許經過本機訪問,默認爲8005;
shutdown:發往此Server用於實現關閉tomcat實例的命令字符串,默認爲SHUTDOWN;
二、Service組件:
Service主要用於關聯一個引擎和與此引擎相關的鏈接器,每一個鏈接器經過一個特定的端口和協議接收入站請求交將其轉發相當聯的引擎進行處理。困此,Service要包含一個引擎、一個或多個鏈接器。
如上面示例中的定義:
<Service name=」Catalina」>
這定義了一個名爲Catalina的Service,此名字也會在產生相關的日誌信息時記錄在日誌文件當中。
Service相關的屬性:
className: 用於實現service的類名,通常都是org.apache.catalina.core.StandardService。
name:此服務的名稱,默認爲Catalina;
三、Connector組件:
進入Tomcat的請求能夠根據Tomcat的工做模式分爲以下兩類:
Tomcat做爲應用程序服務器:請求來自於前端的web服務器,這多是Apache, IIS, Nginx等;
Tomcat做爲獨立服務器:請求來自於web瀏覽器;
Tomcat應該考慮工做情形併爲相應情形下的請求分別定義好須要的鏈接器才能正確接收來自於客戶端的請求。一個引擎能夠有一個或多個鏈接器,以適應多種請求方式。
定義鏈接器可使用多種屬性,有些屬性也只適用於某特定的鏈接器類型。通常說來,常見於server.xml中的鏈接器類型一般有4種:
1) HTTP鏈接器 2) SSL鏈接器 3) AJP 1.3鏈接器 4) proxy鏈接器
如上面示例server.xml中定義的HTTP鏈接器:
<Connector port=」8080″ protocol=」HTTP/1.1″ maxThreads=」150″ connectionTimeout=」20000″ redirectPort=」8443″/>
定義鏈接器時能夠配置的屬性很是多,但一般定義HTTP鏈接器時必須定義的屬性只有「port「,定義AJP鏈接器時必須定義的屬性只有」protocol」,由於默認的協議爲HTTP。如下爲經常使用屬性的說明:
下面是一個定義了多個屬性的SSL鏈接器:
<Connector port=」8443″ maxThreads=」150″ minSpareThreads=」25″ maxSpareThreads=」75″ enableLookups=」false」 acceptCount=」100″ debug=」0″ scheme=」https」 secure=」true」 clientAuth=」false」 sslProtocol=」TLS」 />
四、Engine組件:
Engine是Servlet處理器的一個實例,即servlet引擎,默認爲定義在server.xml中的Catalina。Engine須要defaultHost屬性來爲其定義一個接收全部發往非明肯定義虛擬主機的請求的host組件。如前面示例中定義的:
<Engine name=」Catalina」 defaultHost=」localhost」>
經常使用的屬性定義:
defaultHost:Tomcat支持基於FQDN的虛擬主機,這些虛擬主機能夠經過在Engine容器中定義多個不一樣的Host組件來實現;但若是此引擎的鏈接器收到一個發往非非明肯定義虛擬主機的請求時則須要將此請求發往一個默認的虛擬主機進行處理,所以,在Engine中定義的多個虛擬主機的主機名稱中至少要有一個跟defaultHost定義的主機名稱同名;
name:Engine組件的名稱,用於日誌和錯誤信息記錄時區別不一樣的引擎;
Engine容器中能夠包含Realm、Host、Listener和Valve子容器。
五、Host組件:
位於Engine容器中用於接收請求並進行相應處理的主機或虛擬主機,如前面示例中的定義:
<Host name=」localhost」 appBase=」webapps」 unpackWARs=」true」 autoDeploy=」true」 xmlValidation=」false」 xmlNamespaceAware=」false」> </Host>
經常使用屬性說明:
虛擬主機定義示例:
<Engine name=」Catalina」 defaultHost=」localhost」> <Host name=」localhost」 appBase=」webapps」> <Context path=」」 docBase=」ROOT」/> <Context path=」/bbs」 docBase=」/web/bss」 #path路徑是定義在defaultHost背後的 reloadable=」true」 crossContext=」true」/> </Host> <Host name=」mail.magedu.com」 appBase=」/web/mail」> <Context path=」」 docBase=」ROOT」/> </Host> </Engine>
主機別名定義:
若是一個主機有兩個或兩個以上的主機名,額外的名稱都可以以別名的形式進行定義,以下:
<Host name=」www.ttlsa.com」 appBase=」webapps」 unpackWARs=」true」> <Alias>feiyu.com</Alias> </Host>
六、Context組件:
Context在某些意義上相似於apache中的路徑別名,一個Context定義用於標識tomcat實例中的一個Web應用程序;以下面的定義:
<!– Tomcat Root Context –> <Context path=」」 docBase=」/web/webapps」/> <!– buzzin webapp –> <Context path=」/bbs」 docBase=」/web/threads/bbs」 reloadable=」true」> </Context> <!– chat server –> <Context path=」/chat」 docBase=」/web/chat」/> <!– darian web –> <Context path=」/darian」 docBase=」darian」/>
在Tomcat6中,每個context定義也可使用一個單獨的XML文件進行,其文件的目錄爲$CATALINA_HOME/conf//。能夠用於Context中的XML元素有Loader,Manager,Realm,Resources和WatchedResource。
經常使用的屬性定義有:
七、Realm組件:
一個Realm表示一個安全上下文,它是一個受權訪問某個給定Context的用戶列表和某用戶所容許切換的角色相關定義的列表。所以,Realm就像是一個用戶和組相關的數據庫。定義Realm時唯一必需要提供的屬性是classname,它是Realm的多個不一樣實現,用於表示此Realm認證的用戶及角色等認證信息的存放位置。
八、Valve組件:
Valve相似於過濾器,它能夠工做於Engine和Host/Context之間、Host和Context之間以及Context和Web應用程序的某資源之間。一個容器內能夠創建多個Valve,並且Valve定義的次序也決定了它們生效的次序。Tomcat6中實現了多種不一樣的Valve:
下面是一個常見的使用UserDatabase的配置:
<Realm className=」org.apache.catalina.realm.UserDatabaseRealm」 resourceName=」UserDatabase」/>
下面是一個使用JDBC方式獲取用戶認證信息的配置:
<Realm className=」org.apache.catalina.realm.JDBCRealm」 debug=」99″ driverName=」org.gjt.mm.mysql.Driver」 connectionURL=」jdbc:mysql://localhost/authority」 connectionName=」test」 connectionPassword=」test」 userTable=」users」 userNameCol=」user_name」 userCredCol=」user_pass」 userRoleTable=」user_roles」 roleNameCol=」role_name」 />
八、Valve組件:
Valve相似於過濾器,它能夠工做於Engine和Host/Context之間、Host和Context之間以及Context和Web應用程序的某資源之間。一個容器內能夠創建多個Valve,並且Valve定義的次序也決定了它們生效的次序。Tomcat6中實現了多種不一樣的Valve:
RemoteHostValve和RemoteAddrValve能夠分別用來實現基於主機名稱和基於IP地址的訪問控制,控制自己能夠經過allow或deny來進行定義,這有點相似於Apache的訪問控制功能;以下面的Valve則實現了僅容許本機訪問/probe:
<Context path=」/probe」 docBase=」probe」> <Valve className=」org.apache.catalina.valves.RemoteAddrValve」 allow=」127\.0\.0\.1″/> </Context>
<Server> //頂層類元素,能夠包括多個Service <Service> //頂層類元素,可包含一個Engine,多個Connecter <Connector> //鏈接器類元素,表明通訊接口 <Engine> //容器類元素,爲特定的Service組件處理客戶請求,要包含多個Host <Host> //容器類元素,爲特定的虛擬主機組件處理客戶請求,可包含多個Context <Context> //容器類元素,爲特定的Web應用處理全部的客戶請求 </Context> </Host> </Engine> </Connector> </Service> </Server>
server.xml源碼以下
<?xml version="1.0" encoding="UTF-8"?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <!-- Note: A "Server" is not itself a "Container", so you may not define subcomponents such as "Valves" at this level. Documentation at /docs/config/server.html --> <Server port="8005" shutdown="SHUTDOWN"> <Listener className="org.apache.catalina.startup.VersionLoggerListener" /> <!-- Security listener. Documentation at /docs/config/listeners.html <Listener className="org.apache.catalina.security.SecurityListener" /> --> <!--APR library loader. Documentation at /docs/apr.html --> <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> <!-- Prevent memory leaks due to use of particular java/javax APIs--> <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> <!-- Global JNDI resources Documentation at /docs/jndi-resources-howto.html --> <GlobalNamingResources> <!-- Editable user database that can also be used by UserDatabaseRealm to authenticate users --> <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> </GlobalNamingResources> <!-- A "Service" is a collection of one or more "Connectors" that share a single "Container" Note: A "Service" is not itself a "Container", so you may not define subcomponents such as "Valves" at this level. Documentation at /docs/config/service.html --> <Service name="Catalina"> <!--The connectors can use a shared executor, you can define one or more named thread pools--> <!-- <Executor name="tomcatThreadPool" namePrefix="catalina-exec-" maxThreads="150" minSpareThreads="4"/> --> <!-- A "Connector" represents an endpoint by which requests are received and responses are returned. Documentation at : Java HTTP Connector: /docs/config/http.html Java AJP Connector: /docs/config/ajp.html APR (HTTP/AJP) Connector: /docs/apr.html Define a non-SSL/TLS HTTP/1.1 Connector on port 8080 --> <Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> <!-- A "Connector" using the shared thread pool--> <!-- <Connector executor="tomcatThreadPool" port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /> --> <!-- Define a SSL/TLS HTTP/1.1 Connector on port 8443 This connector uses the NIO implementation. The default SSLImplementation will depend on the presence of the APR/native library and the useOpenSSL attribute of the AprLifecycleListener. Either JSSE or OpenSSL style configuration may be used regardless of the SSLImplementation selected. JSSE style configuration is used below. --> <!-- <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol" maxThreads="150" SSLEnabled="true"> <SSLHostConfig> <Certificate certificateKeystoreFile="conf/localhost-rsa.jks" type="RSA" /> </SSLHostConfig> </Connector> --> <!-- Define a SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2 This connector uses the APR/native implementation which always uses OpenSSL for TLS. Either JSSE or OpenSSL style configuration may be used. OpenSSL style configuration is used below. --> <!-- <Connector port="8443" protocol="org.apache.coyote.http11.Http11AprProtocol" maxThreads="150" SSLEnabled="true" > <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" /> <SSLHostConfig> <Certificate certificateKeyFile="conf/localhost-rsa-key.pem" certificateFile="conf/localhost-rsa-cert.pem" certificateChainFile="conf/localhost-rsa-chain.pem" type="RSA" /> </SSLHostConfig> </Connector> --> <!-- Define an AJP 1.3 Connector on port 8009 --> <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> <!-- An Engine represents the entry point (within Catalina) that processes every request. The Engine implementation for Tomcat stand alone analyzes the HTTP headers included with the request, and passes them on to the appropriate Host (virtual host). Documentation at /docs/config/engine.html --> <!-- You should set jvmRoute to support load-balancing via AJP ie : <Engine name="Catalina" defaultHost="localhost" jvmRoute="jvm1"> --> <Engine name="Catalina" defaultHost="localhost"> <!--For clustering, please take a look at documentation at: /docs/cluster-howto.html (simple how to) /docs/config/cluster.html (reference documentation) --> <!-- <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster"/> --> <!-- Use the LockOutRealm to prevent attempts to guess user passwords via a brute-force attack --> <Realm className="org.apache.catalina.realm.LockOutRealm"> <!-- This Realm uses the UserDatabase configured in the global JNDI resources under the key "UserDatabase". Any edits that are performed against this UserDatabase are immediately available for use by the Realm. --> <Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/> </Realm> <Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <!-- SingleSignOn valve, share authentication between web applications Documentation at: /docs/config/valve.html --> <!-- <Valve className="org.apache.catalina.authenticator.SingleSignOn" /> --> <!-- Access log processes all example. Documentation at: /docs/config/valve.html Note: The pattern used is equivalent to using pattern="common" --> <Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" prefix="localhost_access_log" suffix=".txt" pattern="%h %l %u %t "%r" %s %b" /> </Host> </Engine> </Service> </Server>
由上可得出Tomcat的體系結構:
圖一:Tomcat的體系結構
由上圖可看出Tomca的心臟是兩個組件:Connecter和Container。一個Container能夠選擇多個Connecter,多個Connector和一個Container就造成了一個Service。Service能夠對外提供服務,而Server服務器控制整個Tomcat的生命週期。
組件的生命線「Lifecycle」
Service 和 Server 管理它下面組件的生命週期。
Tomcat 中組件的生命週期是經過 Lifecycle 接口來控制的,組件只要繼承這個接口並實現其中的方法就能夠統一被擁有它的組件控制了,這樣一層一層的直到一個最高級的組件就能夠控制 Tomcat 中全部組件的生命週期,這個最高的組件就是 Server,而控制 Server 的是 Startup,也就是您啓動和關閉 Tomcat。
一個Connecter將在某個指定的端口上偵聽客戶請求,接收瀏覽器的發過來的 tcp 鏈接請求,建立一個 Request 和 Response 對象分別用於和請求端交換數據,而後會產生一個線程來處理這個請求並把產生的 Request 和 Response 對象傳給處理Engine(Container中的一部分),從Engine出得到響應並返回客戶。
Tomcat中有兩個經典的Connector,一個直接偵聽來自Browser的HTTP請求,另一個來自其餘的WebServer請求。Cotote HTTP/1.1 Connector在端口8080處偵聽來自客戶Browser的HTTP請求,Coyote JK2 Connector在端口8009處偵聽其餘Web Server的Servlet/JSP請求。
Connector 最重要的功能就是接收鏈接請求而後分配線程讓 Container 來處理這個請求,因此這必然是多線程的,多線程的處理是 Connector 設計的核心。
Container的體系結構以下:
圖二:Container的體系結構
Container是容器的父接口,該容器的設計用的是典型的責任鏈的設計模式,它由四個自容器組件構成,分別是Engine、Host、Context、Wrapper。這四個組件是負責關係,存在包含關係。一般一個Servlet class對應一個Wrapper,若是有多個Servlet定義多個Wrapper,若是有多個Wrapper就要定義一個更高的Container,如Context。
Context 還能夠定義在父容器 Host 中,Host 不是必須的,可是要運行 war 程序,就必需要 Host,由於 war 中必有 web.xml 文件,這個文件的解析就須要 Host 了,若是要有多個 Host 就要定義一個 top 容器 Engine 了。而 Engine 沒有父容器了,一個 Engine 表明一個完整的 Servlet 引擎。
Tomcat 還有其它重要的組件,如安全組件 security、logger 日誌組件、session、mbeans、naming 等其它組件。這些組件共同爲 Connector 和 Container 提供必要的服務。
圖三:Tomcat Server處理一個HTTP請求的過程
一、用戶點擊網頁內容,請求被髮送到本機端口8080,被在那裏監聽的Coyote HTTP/1.1 Connector得到。
二、Connector把該請求交給它所在的Service的Engine來處理,並等待Engine的迴應。
三、Engine得到請求localhost/test/index.jsp,匹配全部的虛擬主機Host。
四、Engine匹配到名爲localhost的Host(即便匹配不到也把請求交給該Host處理,由於該Host被定義爲該Engine的默認主機),名爲localhost的Host得到請求/test/index.jsp,匹配它所擁有的全部的Context。Host匹配到路徑爲/test的Context(若是匹配不到就把該請求交給路徑名爲「 」的Context去處理)。
五、path=「/test」的Context得到請求/index.jsp,在它的mapping table中尋找出對應的Servlet。Context匹配到URL PATTERN爲*.jsp的Servlet,對應於JspServlet類。
六、構造HttpServletRequest對象和HttpServletResponse對象,做爲參數調用JspServlet的doGet()或doPost().執行業務邏輯、數據存儲等程序。
七、Context把執行完以後的HttpServletResponse對象返回給Host。
八、Host把HttpServletResponse對象返回給Engine。
九、Engine把HttpServletResponse對象返回Connector。
十、Connector把HttpServletResponse對象返回給客戶Browser。