從上圖中能夠看出 Tomcat 的心臟是兩個組件:Connector 和 Container。Connector 組件是能夠被替換,這樣能夠提供給服務器設計者更多的選擇,由於這個組件是如此重要,不只跟服務器的設計的自己,並且和不一樣的應用場景也十分相關,因此一個 Container 能夠選擇對應多個 Connector。多個 Connector 和一個 Container 就造成了一個 Service,Service 的概念你們都很熟悉了,有了 Service 就能夠對外提供服務了,可是 Service 還要一個生存的環境,必需要有人可以給她生命、掌握其生死大權,那就非 Server 莫屬了。因此整個 Tomcat 的生命週期由 Server 控制。目前我們公司用的tomcat的版本Server version:Apache Tomcat/7.0.52.html
Catalina:與開始/關閉shell腳本交互的主類,所以若是要研究啓動和關閉的過程,就從這個類開始看起。java
Server:是整個Tomcat組件的容器,包含一個或多個Service。web
Service:Service是包含Connector和Container的集合,Service用適當的Connector接收用戶的請求,再發給相應的Container來處理。spring
Connector:實現某一協議的鏈接器,如默認的有實現HTTP、HTTPS、AJP協議的。sql
Container:能夠理解爲處理某類型請求的容器,處理的方式通常爲把處理請求的處理器包裝爲Valve對象,並按必定順序放入類型爲Pipeline的管道里。Container有多種子類型:Engine、Host、Context和Wrapper,這幾種子類型Container依次包含,處理不一樣粒度的請求。另外Container裏包含一些基礎服務,如Loader、Manager和Realm。shell
Engine:Engine包含Host和Context,接到請求後仍給相應的Host在相應的Context裏處理。數據庫
Host:就是咱們所理解的虛擬主機。apache
Context:就是咱們所部屬的具體Web應用的上下文,每一個請求都在是相應的上下文裏處理的。api
Wrapper:Wrapper是針對每一個Servlet的Container,每一個Servlet都有相應的Wrapper來管理。瀏覽器
能夠看出Server、Service、Connector、Container、Engine、Host、Context和Wrapper這些核心組件的做用範圍是逐層遞減,並逐層包含。
下面就是些被Container所用的基礎組件:
Loader:是被Container用來載入各類所需的Class。
Manager:是被Container用來管理Session池。
Realm:是用來處理安全裏受權與認證。
1 public abstract interface Service extends Lifecycle 2 { 3 public abstract Container getContainer(); 4 public abstract void setContainer(Container paramContainer); 5 public abstract String getInfo(); 6 public abstract String getName(); 7 public abstract void setName(String paramString); 8 public abstract Server getServer(); 9 public abstract void setServer(Server paramServer); 10 public abstract ClassLoader getParentClassLoader(); 11 public abstract void setParentClassLoader(ClassLoader paramClassLoader); 12 public abstract void addConnector(Connector paramConnector); 13 public abstract Connector[] findConnectors(); 14 public abstract void removeConnector(Connector paramConnector); 15 public abstract void addExecutor(Executor paramExecutor); 16 public abstract Executor[] findExecutors(); 17 public abstract Executor getExecutor(String paramString); 18 public abstract void removeExecutor(Executor paramExecutor); 19 }
從 Service 接口中定義的方法中能夠看出,它主要是爲了關聯 Connector 和 Container,同時會初始化它下面的其它組件,注意接口中它並無規定必定要控制它下面的組件的生命週期。全部組件的生命週期在一個 Lifecycle 的接口中控制。Tomcat 中 Service 接口的標準實現類是 StandardService 它不只實現了 Service 藉口同時還實現了 Lifecycle 接口,這樣它就能夠控制它下面的組件的生命週期了。 StandardService 中主要的幾個方法實現的代碼,下面是 setContainer 和 addConnector 方法的源碼:
1 public void setContainer(Container container) { 2 Container oldContainer = this.container; 3 if ((oldContainer != null) && (oldContainer instanceof Engine)) //判斷當前的這個 Service 有沒有已經關聯了 Container,若是已經關聯了,那麼去掉這個關聯關係 4 ((Engine) oldContainer).setService(null); 5 this.container = container; 6 if ((this.container != null) && (this.container instanceof Engine)) 7 ((Engine) this.container).setService(this); 8 if (getState().isAvailable() && (this.container != null)) { 9 try { 10 this.container.start(); 11 } catch (LifecycleException e) { 12 // Ignore 13 } 14 } 15 if (getState().isAvailable() && (oldContainer != null)) { 16 try { 17 oldContainer.stop(); //若是這個 oldContainer 已經被啓動了,結束它的生命週期 18 } catch (LifecycleException e) { 19 // Ignore 20 } 21 } 22 // Report this property change to interested listeners 23 support.firePropertyChange("container", oldContainer, this.container); 24 }
1 public void addConnector(Connector connector) { 2 synchronized (connectorsLock) { 3 connector.setService(this); 4 Connector results[] = new Connector[connectors.length + 1]; 5 System.arraycopy(connectors, 0, results, 0, connectors.length); 6 results[connectors.length] = connector; 7 connectors = results; 8 if (getState().isAvailable()) { 9 try { 10 connector.start(); 11 } catch (LifecycleException e) { 12 log.error(sm.getString( 13 "standardService.connector.startFailed", 14 connector), e); 15 } 16 } 17 // Report this property change to interested listeners 18 support.firePropertyChange("connector", null, connector); 19 } 20 }
|
Server類是提供一個接口讓其餘程序可以訪問到這個service集合,同時要維護它所包含的全部的Service的生命週期,包括如何初始化,如何結束服務,如何找到別人要訪問的Service。它的標準實現類 StandardServer 實現server這些方法,同時也實現了LifecycleMBeanBase接口的全部方法,LifecycleMBeanBase接口實現了MBeanRegistration並繼承了LifecycleBase接口。LifecycleBase接口實現了Lifecycle接口。因此Lifecycle接口的方法實現都在其它組件中,因此組件的生命週期由包含它的父組件控制。如Server的Start方法和Stop方法就會調用Service組件的相關方法。下面主要看一下 StandardServer 重要的一個方法 addService 的實現:
1 @Override 2 public void addService(Service service) { 3 service.setServer(this); //關聯Server和Service 4 synchronized (servicesLock) { 5 Service results[] = new Service[services.length + 1]; 6 System.arraycopy(services, 0, results, 0, services.length); 7 results[services.length] = service; 8 services = results; 9 if (getState().isAvailable()) { 10 try { 11 service.start(); 12 } catch (LifecycleException e) { 13 // Ignore 14 } 15 } 16 // Report this property change to interested listeners 17 support.firePropertyChange("service", null, service); 18 } 19 }
Tomcat服務器是由一系列可配置的組件構成,其中核心的組件是Catalina Servlet容器,它是全部其餘Tomcat組件的頂層容器。Tomcat的組件在<CATALINA_HOME>/conf/server.xml文件中進行配置,每一個Tomcat組件在server.xml文件中對應一種配置元素。一下代碼以XML的形式展現各類Tomcat組件之間的關係(如下是fat環境的tomcat的server.xml配置):
1 <?xml version='1.0' encoding='utf-8'?> 2 <Server port="8005" shutdown="SHUTDOWN"> 3 <Listener className="org.apache.catalina.core.AprLifecycleListener" SSLEngine="on" /> 4 <Listener className="org.apache.catalina.core.JasperListener" /> 5 <Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener" /> 6 <Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener" /> 7 <Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener" /> 8 <GlobalNamingResources> 9 <Resource name="UserDatabase" auth="Container" 10 type="org.apache.catalina.UserDatabase" 11 description="User database that can be updated and saved" 12 factory="org.apache.catalina.users.MemoryUserDatabaseFactory" 13 pathname="conf/tomcat-users.xml" /> 14 </GlobalNamingResources> 15 <Service name="Catalina"> 16 <Connector port="8080" protocol="HTTP/1.1" 17 socketBuffer="9000" 18 enableLookups="false" 19 tcpNoDelay="true" 20 minSpareThreads="20" 21 maxThreads="1024" 22 connectionTimeout="5000" 23 maxHttpHeaderSize="32768" 24 acceptCount="150" 25 redirectPort="8443" /> 26 <Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /> 27 <Engine name="Catalina" defaultHost="localhost"> 28 <Realm className="org.apache.catalina.realm.LockOutRealm"> 29 <Realm className="org.apache.catalina.realm.UserDatabaseRealm" 30 resourceName="UserDatabase"/> 31 </Realm> 32 <Host name="localhost" appBase="/opt/ctrip/web/work" 33 unpackWARs="true" autoDeploy="true"> 34 35 <Context path="/btbjob" crossContext="true" reloadable="true" docBase="/opt/ctrip/web/jobws.btborder.flight.charter-jobws-btborder/work"/> 36 <Valve className="org.apache.catalina.valves.AccessLogValve" directory="/opt/logs/tomcat" 37 prefix="access." suffix=".log" 38 pattern="%h %l %u %t "%r" %s %b %T" /> 39 </Host> 40 </Engine> 41 </Service> 42 </Server>
|
元素名
|
屬性
|
解釋
|
server |
port |
指定一個端口,這個端口負責監聽關閉tomcat的請求 |
shutdown |
指定向端口發送的命令字符串 |
|
service |
name |
指定service的名字 |
Connector(表示客戶端和service之間的鏈接) |
port |
指定服務器端要建立的端口號,並在這個斷口監聽來自客戶端的請求 |
protocol |
瀏覽器請求必須爲HTTP1.1 若是使用AJP處理器,該值必須爲AJP/1.3 |
|
socketBuffer |
設Socket輸出緩衝區的大小(以字節爲單位),-1表示禁止緩衝,默認值爲9000字節 |
|
tcpNoDelay |
爲true時,能夠提升性能。默認值爲true |
|
minSpareThreads |
設當鏈接器第一次啓協建立線程的數目,確保至少有這麼多的空閒線程可用。默認值爲4 |
|
maxHttpHeaderSize |
HTTP請求和響應頭的最大量,以字節爲單位,默認值爲4096字節 |
|
maxSpareThreads |
容許存在空閒線程的最大數目,默認值爲50 |
|
enableLookups |
若是爲true,則能夠經過調用request.getRemoteHost()進行DNS查詢來獲得遠程客戶端的實際主機名,若爲false則不進行DNS查詢,而是返回其ip地址 |
|
redirectPort |
指定服務器正在處理http請求時收到了一個SSL傳輸請求後重定向的端口號 |
|
acceptCount |
指定當全部可使用的處理請求的線程數都被使用時,能夠放處處理隊列中的請求數,超過這個數的請求將不予處理 |
|
connectionTimeout |
指定超時的時間數(以毫秒爲單位) |
|
Engine(表示指定service中的請求處理機,接收和處理來自Connector的請求) |
defaultHost |
指定缺省的處理請求的主機名,它至少與其中的一個host元素的name屬性值是同樣的 |
Context(表示一個web應用程序,一般爲WAR文件,關於WAR的具體信息見servlet規範) |
docBase |
應用程序的路徑或者是WAR文件存放的路徑 |
path |
表示此web應用程序的url的前綴,這樣請求的url爲http://localhost:8080/path/**** |
|
reloadable |
這個屬性很是重要,若是爲true,則tomcat會自動檢測應用程序的/WEB-INF/lib 和/WEB-INF/classes目錄的變化,自動裝載新的應用程序,咱們能夠在不重起tomcat的狀況下改變應用程序 |
|
host(表示一個虛擬主機) |
name |
指定主機名 |
appBase |
應用程序基本目錄,即存放應用程序的目錄 |
|
autoDeploy |
指示Tomcat運行時,若有新的WEB程序加開appBase指定的目錄下,是否爲自動佈署,默認值爲true |
|
unpackWARs |
若是爲true,則tomcat會自動將WAR文件解壓,不然不解壓,直接從WAR文件中運行應用程序 |
|
Logger(表示日誌,調試和錯誤信息) |
className |
指定logger使用的類名,此類必須實現org.apache.catalina.Logger 接口 |
prefix |
指定log文件的前綴 |
|
suffix |
指定log文件的後綴 |
|
timestamp |
若是爲true,則log文件名中要加入時間,以下例:localhost_log.001-10-04.txt |
|
Realm(表示存放用戶名,密碼及role的數據庫) |
className |
指定Realm使用的類名,此類必須實現org.apache.catalina.Realm接口 |
Valve(功能與Logger差很少,其prefix和suffix屬性解釋和Logger 中的同樣) |
className |
指定Valve使用的類名,如用org.apache.catalina.valves.AccessLogValve類能夠記錄應用程序的訪問信息 |
directory |
指定log文件存放的位置 |
|
pattern |
有兩個值,common方式記錄遠程主機名或ip地址,用戶名,日期,第一行請求的字符串,HTTP響應代碼,發送的字節數。combined方式比common方式記錄的值更多 |
tomcat部署方式有三種:
<Context path="/hello" docBase="D:eclipse3.2.2forwebtoolsworkspacehelloWebRoot" debug="0" privileged="true">
</Context>
<Context path="/hello" docBase="D:eclipse3.2.2forwebtoolsworkspacehelloWebRoot" debug="0" privileged="true">
</Context>
注:一個Tomcat若要部署多個項目,在Server.xml文件添加<Context/>如:
<Context path="/btbjob_one" crossContext="true" reloadable="true" docBase="/opt/ctrip/web/jobws.btborder.flight.charter-jobws-btborder/work"/>
<Context path="/btbjob_two" crossContext="true" reloadable="true" docBase="/opt/ctrip/web/jobws.btborder.flight.charter-jobws-btborder/work"/>
熱部署是指在你對項目代碼(不管是JSP、JAVA類,甚至是配置文件)進行了修改時,在不重啓WEB服務器前提下能讓修改生效。
進入myEclipse - > preference -> Tomcat 7.x -> JDK , 在Optional Java VM arguments中填入 -Dcom.sun.management.jmxremote=true 以下圖:
Tomcat Server處理請求的過程,以下以HTTP請求爲例:
由上圖可見,Request的解析和加工過程不是在一個方法裏搞定,而是信息流動過程當中逐步解析的,不一樣層次的處理器解析不一樣層次的信息,在解析過程同時作了些判斷和攔截的工做,好比當發現是要訪問WEB-INF的資源,會直接返回錯誤給客戶端等等。
1 The JAVA_HOME environment variable is not defined This environment variable is needed to run this program;
Re:沒有在tomcat的配置文件.bash_profile中設置環境變量JAVA_HOME,具體設置方法爲:加入以下幾行:
JAVA_HOME=/home/tomcat/j2sdk1.4.2_08(具體值要以實際的jdk安裝路徑爲準)
export JAVA_HOMECLASSPATH=/home/tomcat/j2sdk1.4.2_08/lib/tools.jar:/home/tomcat/j2sdk1.4.2_08/lib/dt.jar
export CLASSPATH
2 Error occurred during initialization of VM Could not reserve enough space for object heap
Re:在tomcat的bin目錄下,catalina.sh文件的tomcat內存參數配置過大,超過機器可用內存總數形成,修改到適當的值便可,修改的參數爲:JAVA_OPTS="-Xms50m -Xmx60m"
3 tomcat啓動時報某個目錄沒有權限,啓動失敗,或者不能執行某些jsp頁
Re:tomcat須要tomcat用戶具備一些目錄和文件的相應權限, 全部目錄應該具備讀寫執行(瀏覽)的權限,jsp,class文件應該最少具備讀權限, 一些文件須要寫權限,下面是已知的須要讀寫權限文件的列表:
$CATALINA_HOME/logs下全部文件
$CATALINA_HOME/work下全部文件
$CATALINA_HOME/publish/main/count.txt文件
$CATALINA_HOME/publish/chatroom/resource下的全部.xml文件
全部上傳圖片目錄都須要寫權限。
改變文件目錄權限的方法:執行下面命令,設置全部的tomcat安裝下的文件和目錄,能夠保證執行,可是不是很安全。
1. 設置tomcat上級目錄/opt全部用戶都有讀寫執行權限:
chmod 777 [tomcat的上級目錄]
2. 設置tomcat目錄下的全部文件的屬主爲deploy:
chown -R tomcat [tomcat安裝目錄]
3. 設置全部tomcat下的全部文件和目錄的屬主(deploy)具備讀寫執行權限
chmod 700 -R /opt/tomcat
注意:公司測試環境tomcat所屬主爲deploy,切勿使用root主去啓動tomcat.
4 執行startup.sh文件後告訴地址已經使用,致使tomcat不能啓動
Re:多是前一次執行./shutdown.sh文件關閉tomcat時沒有中止已經啓動的Java進程,而這個進程仍然在監聽tomcat所使用的端口,或者有另一個tomcat正在運行,server.xml文件中的監聽端口和當前tomcat衝突。
使用下面命令查看當前系統是否有正在監聽的端口(8080--webcache, 90--www或http).
1. 列出全部系統正在監聽的端口和綁定的地址netstat -l
2. 找出當前系統中的全部進程,管道符號過濾輸出顯示包含java字符串的行
ps -A |grep java
3. 結束一個指定的進程:
kill [進程號]
4. 強制殺死一個進程:
kill -9 [進程號]
若是肯定不是別的tomcat運行致使的衝突或者沒有java進程運行能夠再次運行startup.sh文件啓動tomcat
tomcat運行時錯誤
1. org.apache.commons.dbcp.SQLNestedException: Cannot create PoolableConnectionFactory (Network error IOException: Connection refused: connect)
2. Caused by: java.sql.SQLException: Network error IOException: Connection refused: connect
3. Caused by: java.net.ConnectException: Connection refused: connect
Re:數據庫未開狀況下運行tomcat出現的問題,把數據庫打開就好了
4.java.lang.NoSuchMethodError: org.objectweb.asm.ClassVisitor.visit(IILjava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/lang/String;)V
at net.sf.cglib.core.ClassEmitter.begin_class(ClassEmitter.java:77) 這個問題是最最多見的,第一次整合ssh的時候會發現這個問題,有時候刪除掉相關的包仍是會衝突。因此解決辦法我通常是:
Re:把MyEclipse中的hibernate中的有關ASM的包所有刪除,將spring中asm包拷貝進去重啓就Ok了,有時候須要刪除其餘文件,到網上找找吧;
還有個解決辦法:Spring 和 Hibernate 共用的一些 jar 文件發生了版本衝突, 刪除 WEB-INF/lib/asm-2.2.3.jar 而後重啓 Tomcat.
5 .javax.servlet.jsp.JspException: Invalid argument looking up property usersVO.account of bean loginForm
Re,通常提示這種錯誤表示VO中的form沒有實例化,在reset方法中new一下就Ok了。養成良好的編碼習慣能夠避免這種簡單錯誤。
6.嚴重: Exception loading sessions from persistent storage
Re:tomcat安裝目錄\work\Catalina\localhost\{webAppName}\SESSIONS.ser,刪除此文件
出現404錯誤是由於你所請求的頁面不可用!這是response對象的http響應中的狀態行404表示當前請求的頁面不可用!200表示測試經過。500表示服務器內部發生錯誤等!
具體錯誤碼對用的信息參見:http://blog.csdn.net/lidawei201/article/details/8482006
tomcat8以前的默認編碼是ISO-8859-1,tomcat8的默認編碼是UTF-8.
解決中文亂碼的問題:若是請求方式GET.能夠更改${CATALINA_HOME}/conf/server.xml中對應的Connector中指定URIEncoding="UTF-8"參數.
若是請求方式POST.能夠經過Filter來設置編碼.Tomcat7.x (已經將這個Filter加入Tomcat內置了,直接複製一下代碼到你的項目web.xml中)
1 <filter> 2 <filter-name>setCharacterEncodingFilter</filter-name> 3 <filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class> 4 <init-param> 5 <param-name>encoding</param-name> 6 <param-value>UTF-8</param-value> 7 </init-param> 8 </filter> 9 <filter-mapping> 10 <filter-name>setCharacterEncodingFilter</filter-name> 11 <url-pattern>/*</url-pattern> 12 </filter-mapping>
若是這樣設置仍是有亂碼問題,須要考慮下數據庫的編碼.