1. 程式人生 > >Servlet和Tomcat相關知識

Servlet和Tomcat相關知識

Java Servlet是用Java編寫的伺服器端程式。其主要功能在於互動式地瀏覽和修改資料,生成動態Web內容。狹義的Servlet是指Java語言實現的一個介面,廣義的Servlet是指任何實現了這個Servlet介面的類別,一般情況下,人們將Servlet理解為後者。Servlet運行於支援Java的應用伺服器中。從實現上講,Servlet可以響應任何型別的請求,但絕大多數情況下Servlet只用來擴充套件基於HTTP協議的Web伺服器。

Servlet工作模式

  • 客戶端傳送請求至伺服器 
  • 伺服器啟動並呼叫Servlet,Servlet根據客戶端請求生成響應內容並將其傳給伺服器 
  • 伺服器將響應返回客戶端 

通用Servlet

一般的,通用Servlet由javax.servlet.GenericServlet實現Servlet介面。程式設計人員可以通過使用或繼承這個類來實現通用Servlet應用。

HttpServlet

javax.servlet.http.HttpServlet實現了專門用於響應HTTP請求的Servlet,提供了響應請求的doGet()和doPost()方法。

生命週期

當servlet被部署在應用伺服器中(應用伺服器中用於管理Java元件的部分被抽象成為容器)以後,由容器控制servlet的生命週期。除非特殊制定,否則在容器啟動的時候,servlet是不會被載入的,servlet只會在第一次請求的時候被

載入例項化。servlet一旦被載入,一般不會從容器中刪除,直至應用伺服器關閉或重新啟動。但當容器做記憶體回收動作時,servlet有可能被刪除。也正是因為這個原因,第一次訪問servlet所用的時間要大大多於以後訪問所用的時間。

注:servlet在伺服器中的執行:1.載入 ->2.初始化 - > 3.呼叫 - 4.銷燬  

servlet的生命週期在【2.初始化】後開始其生命週期,在【4.銷燬】後結束其生命週期

與JSP的關係

Java伺服器頁面(JSP)是HttpServlet的擴充套件。由於HttpServlet大多是用來響應HTTP請求,並返回Web頁面(例如HTML

XML),所以不可避免地,在編寫servlet時會涉及大量的HTML內容,這給servlet的書寫效率和可讀性帶來很大障礙,JSP便是在這個基礎上產生的。其功能是使用HTML的書寫格式,在適當的地方加入Java程式碼片斷,將程式設計師從複雜的HTML中解放出來,更專注於servlet本身的內容。JSP在首次被訪問的時候被應用伺服器轉換為servlet,在以後的執行中,容器直接呼叫這個servlet,而不再訪問JSP頁面。JSP的實質仍然是servlet。

Servlet 2.5的新特徵

  1) 基於最新的J2SE 5.0開發的。 

  2) 支援annotations 。 

  3) web.xml中的幾處配置更加方便。 

  4) 去除了少數的限制。 

      5) 優化了一些例項

Servlet裡的過濾器

(1)過濾器的主要作用

1,任何系統或網站都要判斷使用者是否登入。

2,網路聊天系統或論壇,功能是過濾非法文字

3,統一解決編碼

(2)建立一個過濾器:

1,生成一個普通的class類,實現Filter介面(javax.servlet.Filter;)。

2,重寫接口裡面的三個方法:init,doFilter,destroy。

3,然後在web.xml配置過濾器。

Servlet裡的監聽器

(1)監聽器的作用:自動執行一些操作。

三種servlet監聽器

對request的監聽。對session的監聽。對application的監聽。

(2)建立一個session監聽器:

1,生成一個普通的class類,如果是對session的監聽,則實現HttpSessionListener。

2,然後重寫裡面的五個方法。

Sevlet解決執行緒不安全

Servlet體系結構是建立在Java多執行緒機制之上的,它的生命週期是由Web容器負責的。當客戶端第一次請求某個Servlet時,Servlet容器將會根據web.xml配置檔案例項化這個Servlet類。當有新的客戶端請求該Servlet時,一般不會再例項化該Servlet類,也就是有多個執行緒在使用這個例項。Servlet容器會自動使用執行緒池等技術來支援系統的執行當兩個或多個執行緒同時訪問同一個Servlet時,可能會發生多個執行緒同時訪問同一資源的情況,資料可能會變得不一致。

1 public class ConcurrentTest extends HttpServlet {
 2     PrintWriter output;
 3     @Override
 4     protected void service(HttpServletRequest request, HttpServletResponse response)
 5             throws ServletException, IOException {
 6         String  username;
 7         response.setContentType("text/html;charset=gb2312");
 8         username=request.getParameter("username");
 9         output=response.getWriter();
10         try {
11             //為了突出併發問題,在這設定一個延時
12             Thread.sleep(5000);
13             output.println("使用者名稱:"+username+"<BR>"); 
14         } catch (Exception e) {
15             e.printStackTrace();
16         }
17     }
18 }

假設已在web.xml配置檔案中註冊了該Servlet,現有兩個使用者a和b同時訪問該Servlet(可以啟動兩個IE瀏覽器,或者在兩臺機器上同時訪問),即同時在瀏覽器中輸入:

  a: http://localhost:8080/ServletTest/ConcurrentTest?Username=a
  b: http://localhost:8080/ServletTest/ConcurrentTest?Username=b

則瀏覽器a輸出為空,瀏覽器b輸出:使用者名稱:a 使用者名稱:b

由於b執行緒對例項變數output的修改覆蓋了a執行緒對例項變數output的修改,從而導致了使用者a的資訊顯示在了使用者b的瀏覽器上。如果在a執行緒執行輸出語句時,b執行緒對output的修改還沒有重新整理到主存,那麼將不會出現圖2所示的輸出結果,因此這只是一種偶然現象,但這更增加了程式潛在的危險性。
設計執行緒安全的Servlet
通過上面的分析,我們知道了例項變數不正確的使用是造成Servlet執行緒不安全的主要原因。

1、實現 SingleThreadModel 介面

如果一個Servlet被這個介面指定,那麼在這個Servlet中的service方法將不會有兩個執行緒被同時執行,當然也就不存線上程安全的問題
2、同步對共享資料的操作
使用synchronized 關鍵字能保證一次只有一個執行緒可以訪問被保護的區段,
3、避免使用例項變數
本例項中的執行緒安全問題是由例項變數造成的,只要在Servlet裡面的任何方法裡面都不使用例項變數,那麼該Servlet就是執行緒安全的。

此部分參考連結: http://www.cnblogs.com/gw811/archive/2012/09/07/2674859.html

Tomcat

Tomcat是一個免費的開源的Serlvet容器,它是Apache基金會的Jakarta專案中的一個核心專案,由Apache、Sun和其它一些公司及個人共同開發而成。由於有了Sun的參與和支援,最新的Servlet和Jsp規範總能在 Tomcat中得到體現。

儘管Tomcat也可以作為獨立的Java Web伺服器,但在對靜態資源(HTML、影象檔案等)的處理速度,Web伺服器管理等方面都不如Apache、IIS伺服器等其他專業的HTTP伺服器,因此在實際應用中,常常把Tomcat與其他的HTTP伺服器整合使用。對於不支援Servlet/JSP的HTTP伺服器,可以通過Tomcat伺服器來執行Servlet/JSP元件。

當Tomcat與其他HTTP伺服器整合時,Tomcat伺服器的工作模式通常為程序外的Servlet容器,Tomcat伺服器與其他HTTP伺服器之間通過專門的外掛來通訊。

Tomcat的目錄結構

$CATALINA_HOME   Tomcat安裝目錄下面有
  • bin: 啟動和關閉Tomcat指令碼檔案。
  • conf: Tomcat伺服器的各種配置檔案,包括:server.xml、web.xml、catalina.policy等。
  • lib: Tomcat伺服器和所有web應用可以訪問的jar包。
  • logs: Tomcat的日誌檔案。
  • webapps: Tomcat自帶的兩個web應用:admin和manager,用來管理Tomcat的Web服務。
  • work: JSP經過Tomcat編譯後生成的Servlet。
  • temp: Tomcat執行時的臨時檔案。

Tomcat常用配置檔案

server.xml:Tomcat中最重要的配置檔案,定義了tomcat的體系結構,包括聯結器埠、連線數、叢集、虛擬目錄、訪問日誌等的設定。

context.xml:全域性context的配置檔案,包括JNDI等資訊的配置。

tocmat-users.xml:Tocmat管理員身份的配置檔案,關鍵是設定管理員賬號的密碼。

logging.properties:Tocmat日誌配置檔案,可以修改預設的Tocmat日誌路徑和名稱。

Tomcat日誌配置

Tomcat日誌資訊包括訪問日誌和執行日誌。

訪問日誌用於對使用者訪問系統的行為進行跟蹤記錄,主要記錄使用者訪問的時間、對應的IP地址、訪問的資料等資訊。記錄訪問日誌主要是基於對系統安全的考慮,對系統中一些重要、敏感資訊的資料訪問歷史進行記錄,便於對資源的訪問歷史進行追蹤,對於敏感資訊未經授權訪問等進行事後追查有一定幫助。但記錄訪問日誌會對伺服器效能產生一定的影響,在生產系統中需要慎用。

執行日誌主要記錄程式執行的一些資訊,其中的異常錯誤資訊可以為我們定位錯誤。從6.0版本開始,Tomcat的日誌介面採用是對Apache Commons Logging日誌介面進行獨立封裝,預設配置下,該日誌介面採用硬編碼使用java.util.logging日誌框架。

由於Tomcat釋出版本中獨立封裝的Apache Commons Logging介面並沒有對介面完全實現,如果要選擇不同的日誌框架就需要將該日誌介面替換為完全實現的版本。

預設配置下,Tomcat是不記錄訪問日誌的,可以通過如下配置允許Tomcat記錄訪問日誌:

修改$CATALINA_HOME/server.xml,在Host標籤下,找到如下配置資訊,去掉兩端的註釋就會啟用訪問日誌記錄功能:

<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" 

prefix="localhost_access_log." suffix=".txt" pattern="common" resolveHosts="false"/>

通過對pattern項的修改,可以改變日誌輸出的內容。該項值可以為: common 與 combined,對應的日誌輸出內容如下所示:

common: %h %l %u %t %r %s %b

combined: %h %l %u %t %r %s %b %{Referer}i %{User-Agent}i

pattern 也可以根據需要自由組合, 例如 pattern="%h %l",對 於各 fields 欄位的含義請參照Tomcat官方文件。

在不同的環境下,需要設定不同的日誌級別,在生產環境中,為了提高效率和穩定性,一般會將日誌級別設定為相對較高的級別,而開發環境中為了跟蹤程式流程,可以將日誌級別調整為較低的級別。不同日誌框架有不同的日誌級別,常用的日誌框架對應級別如下:

Java.util.logging對應的日誌級別由高到低分別為:

severe > warning > info > config > fine > finer > finest

org.apache.log4j對應的日誌級別由高到低分別為:

fatal > error > warn > info > debug > trace

在預設配置下,Tomcat採用Java.util.logging日誌框架,對應的配置檔案為$CATALINA_HOME/ logging.properties,常用的日誌級別設定方法如下:

設定catalina日誌的級別為:FINE

1catalina.org.apache.juli.FileHandler.level = FINE

禁用catalina日誌的輸出:

1catalina.org.apache.juli.FileHandler.level = OFF

設定catalina所有的日誌訊息均輸出:

1catalina.org.apache.juli.FileHandler.level = ALL

Log4j是目前應用最廣的日誌框架,可以使用Log4j替換Tomcat預設採用的java.util.logging日誌框架,步驟如下:

建立log4j配置檔案log4j.properties ,儲存在$CATALINA_HOME/lib 下。

從Apache官網Log4J專案下載Log4J(1.2版本以後)。

從Apache官網Tomcat專案下載tomcat-juli.jar和tomcat-juli-adapters.jar。

複製log4j.jar、tomcat-juli-adapters.jar到$CATALINA_HOME/lib下。

用tomcat-juli.jar覆蓋$CATALINA_HOME/bin下的同名檔案。

刪除Tomcat的預設日誌配置檔案$CATALINA_HOME/conf/ logging.properties,以避免生成一些冗餘的空日誌檔案。

Tomcat 組織結構

引用自《Tomcat web開發及整合應用》張巨集偉 編著

Tomcat是一個基於元件的伺服器,它的構成元件都是可配置的,其中最外層的元件是CatalinaServlet容器,其他的元件按照一定的格式要求配置在這個頂層容器中。
Tomcat的各個元件是在<TOMCAT_HOME>\conf\server.xml檔案中配置的(Localhost的埠就是在這裡設定的),Tomcat伺服器預設情況下對各種元件都有預設的實現,下面通過分析server.xml檔案來理解Tomcat的各個元件是如何組織的。server.xml檔案的基本組成結構如下。

<Server>                    頂層類元素:一個配置檔案中只能有一個<Server>元素,可包含多個Service。
   <Service>               頂層類元素:本身不是容器,可包含一個Engine,多個Connector。
       <Connector/>         聯結器類元素:代表通訊介面。
          <Engine>   容器類元素:為特定的Service元件處理所有客戶請求,可包含多個Host。
             <Host>    容器類元素:為特定的虛擬主機處理所有客戶請求,可包含多個Context。
                <Context>   容器類元素:為特定的Web應用處理所有客戶請求。
                </Context>
              </Host>
             </Engine>
     </Service>
</Server>
以上的類XML的程式碼就是server.xml檔案的基本組成結構,一個元素代表一個元件。下面分別介紹這些元件。
.1 Server元件
Server元件對應<Server>元素,它是配置檔案的最頂層元素,代表一個伺服器。一個配置檔案中只能有一個<Server>元素。
.2 Service元件

Service元件是一些Connector元件的集合,它本身不是一個容器,所以在這裡不能定義日誌等元件。一個Service元件中只能有一個Engine元件,可以包含多個Connector元件。

.3 Connector元件
Connector元件表示一個介面,通過這個介面接收客戶的請求,然戶傳送給其他的容器元件,最後再把伺服器的響應結果傳遞給客戶。
.4容器類元素
上面介紹的3個元件本身並不能處理客戶請求,也不能生成響應。Tomcat中只有3個元件是可以處理客戶請求並生成響應的,這3個元件分別是EngineHostContext元件。這3個元件分別代表了不同的服務範圍,通過巢狀關係可以知道3個元件的範圍有如下的關係:Engine>Host>Context。
    Engine元件下可以包含多個Host元件,它為特定的Service元件處理所有客戶請求。
    一個Host元件代表一個虛擬主機,一個虛擬主機中可以包含多個Web應用(Context元件)。
    Context元件代表一個Web應用。
Tomcat的各個元件關係,可以用下圖描述。

一個JavaWeb application在Tomcat中與一個Context元素對應,也就是說一個Context元素定義了一個Java Web application,它們是一一對應的關係。
在一個Java Web應用中可以包含如下內容:
    Servlet
    JSP頁面
    Java類
    靜態資源(HTML文件、圖片等)
    描述Web應用的描述檔案
客戶每次提出請求時指定要訪問的資源,如果客戶沒有指定具體資源,Tomcat使用預設的資源響應客戶,顯示資料夾中的資源列表或者提示錯誤。相應服務的過程如下:

Tomca的心臟是兩個元件:Connecter和Container。一個Container可以選擇多個Connecter,多個Connector和一個Container就形成了一個Service。Service可以對外提供服務,而Server伺服器控制整個Tomcat的生命週期。

  • 元件的生命線“Lifecycle”

    Service 和 Server 管理它下面元件的生命週期。 
    Tomcat 中元件的生命週期是通過 Lifecycle 介面來控制的,元件只要繼承這個介面並實現其中的方法就可以統一被擁有它的元件控制了,這樣一層一層的直到一個最高階的元件就可以控制 Tomcat 中所有元件的生命週期,這個最高的元件就是 Server,而控制 Server 的是 Startup,也就是您啟動和關閉 Tomcat。

Tomca的兩大元件:Connecter和Container

Connecter元件

一個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 設計的核心。

Tomcat 還有其它重要的元件,如安全元件 security、logger 日誌元件、session、mbeans、naming 等其它元件。這些元件共同為 Connector 和 Container 提供必要的服務。

Tomcat Server處理一個HTTP請求的過程

 
              圖三:Tomcat Server處理一個HTTP請求的過程

Tomcat Server處理一個HTTP請求的過程

1、使用者點選網頁內容,請求被髮送到本機埠8080,被在那裡監聽的Coyote HTTP/1.1 Connector獲得。 
2、Connector把該請求交給它所在的Service的Engine來處理,並等待Engine的迴應。 
3、Engine獲得請求localhost/test/index.jsp,匹配所有的虛擬主機Host。 
4、Engine匹配到名為localhost的Host(即使匹配不到也把請求交給該Host處理,因為該Host被定義為該Engine的預設主機),名為localhost的Host獲得請求/test/index.jsp,匹配它所擁有的所有的Context。Host匹配到路徑為/test的Context(如果匹配不到就把該請求交給路徑名為“ ”的Context去處理)。 
5、path=“/test”的Context獲得請求/index.jsp,在它的mapping table中尋找出對應的Servlet。Context匹配到URL PATTERN為*.jsp的Servlet,對應於JspServlet類。 
6、構造HttpServletRequest物件和HttpServletResponse物件,作為引數呼叫JspServlet的doGet()或doPost().執行業務邏輯、資料儲存等程式。 
7、Context把執行完之後的HttpServletResponse物件返回給Host。 
8、Host把HttpServletResponse物件返回給Engine。 
9、Engine把HttpServletResponse物件返回Connector。 
10、Connector把HttpServletResponse物件返回給客戶Browser。

此部分參考連結 http://www.cnblogs.com/guanyuan/p/3494374.html
http://www.cnblogs.com/zhouyuqin/p/5143121.html#wiz_toc_2

Tomcat 常見問題總結

JVM記憶體溢位(OOM),分為堆記憶體溢位和PermGen區記憶體溢位:

java.lang.OutOfMemoryError: PermGen space

PermGen space(Permanent Generation space),是指記憶體的永久儲存區域,主要用於存放Class和Meta資訊的,Class在被Loader時就會被放到PermGen space中, 它和存放類例項(Instance)的Heap區域不同,GC(Garbage Collection)不會在主程式執行期對其進行清理,所以如果應用中有很多CLASS的話,就很可能出現PermGen space錯誤。如果載入的Class超過MaxPermSize,就會丟擲該異常,可以通過調整MaxPermSize進行解決。

java.lang.OutOfMemoryError: Java heap space 

JVM堆是指java程式執行過程中JVM可以調配使用的記憶體空間。JVM在啟動的時候會自動設定Heap size的值,其初始空間(-Xms)是實體記憶體的1/64,最大空間(-Xmx)是實體記憶體的1/4。可以利用JVM提供的-Xmn -Xms -Xmx等選項可進行設定。Heap size 的大小是Young Generation 和Tenured Generaion 之和。在JVM中如果98%的時間是用於GC且可用的Heap size 不足2%的時候將丟擲此異常資訊。

JDK安裝及JAVA_HOME設定

啟動不成功,沒有日誌,一般是JDK安裝不正確或沒有設定環境變數。

大量使用者訪問時瀏覽器沒有響應

併發執行緒數設定太小,調整$CATALINA/conf/server.xml中聯結器對應的請求處理執行緒數。

參考連結:http://www.cnblogs.com/doit8791/archive/2012/10/27/2742768.html