Tomcat系列之Java技術詳解

技術小美發表於2017-11-17

大綱

一、概述

二、Java

三、Servlet與JSP

四、Tomcat

注,本博文是從運維的角度來說明Java相關技術,不涉及開發相關內容。主要寫給與我一樣做運維的博友進行參考!(現在的部落格,操作多、理論少,在這一篇部落格我主要和大家說一說理論知識)(說明:本博文的一些圖片自於開源社群與官方網站並不是所有內容全是原創)


一、概述

1.前言

在前面幾篇部落格中,我們和大家說了負載均衡器伺服器、Web伺服器、反向代理伺服器、快取伺服器,從這篇部落格開始我們和大家說說應用程式伺服器,對於上述內容不瞭解的博友可以去參考一下我們前幾篇的部落格。在應用程式中最出名的有兩種一種是PHP,另一種是JSP。他們都是用來進行Web開發的,特別是進行電子商務網站的開發,應用的特別多。對於我們運維來說肯定是不需要開發的。但我們得進行應用程式伺服器維護的工作。前面我們和大家多次聊了PHP的應用伺服器維護如,LAMP環境的搭建、LNMP環境搭建等。在這篇部落格中我們主要和大家聊一聊JSP服器的應用。在說JSP的相關知識之前,我們先來回憶一下PHP相關知識點。


2.PHP相關知識

(1).PHP簡介

PHP是通用伺服器端指令碼程式語言,其主要用於web開發以實現動態web頁面,它也是最早實現將指令碼嵌入HTML原始碼文件中的伺服器端指令碼語言之一。同時,php還提供了一個命令列介面,因此,其也可以在大多數系統上作為一個獨立的shell來使用。


Rasmus Lerdorf於1994年開始開發PHP,它是初是一組被Rasmus Lerdorf稱作“Personal Home Page Tool” 的Perl指令碼, 這些指令碼可以用於顯示作者的簡歷並記錄使用者對其網站的訪問。後來,Rasmus Lerdorf使用C語言將這些Perl指令碼重寫為CGI程式,還為其增加了執行Web forms的能力以及與資料庫互動的特性,並將其重新命名為“Personal Home Page/Forms Interpreter”或“PHP/FI”。此時,PHP/FI已經可以用於開發簡單的動態web程式了,這即是PHP 1.0。1995年6月,Rasmus Lerdorf把它的PHP釋出於comp.infosystems.www.authoring.cgi Usenet討論組,從此PHP開始走進人們的視野。1997年,其2.0版本釋出。


1997年,兩名以色列程式設計師Zeev Suraski和Andi Gutmans重寫的PHP的分析器(parser)成為PHP發展到3.0的基礎,而且從此將PHP重新命名為PHP: Hypertext Preprocessor。此後,這兩名程式設計師開始重寫整個PHP核心,並於1999年釋出了Zend Engine 1.0,這也意味著PHP 4.0的誕生。2004年7月,Zend Engine 2.0釋出,由此也將PHP帶入了PHP5時代。PHP5包含了許多重要的新特性,如增強的物件導向程式設計的支援、支援PDO(PHP Data Objects)擴充套件機制以及一系列對PHP效能的改進。


(2).PHP Zend Engine

Zend Engine是開源的、PHP指令碼語言的直譯器,它最早是由以色列理工學院(Technion)的學生Andi Gutmans和Zeev Suraski所開發,Zend也正是此二人名字的合稱。後來兩人聯合創立了Zend Technologies公司。


Zend Engine 1.0於1999年隨PHP 4釋出,由C語言開發且經過高度優化,並能夠做為PHP的後端模組使用。Zend Engine為PHP提供了記憶體和資源管理的功能以及其它的一些標準服務,其高效能、可靠性和可擴充套件性在促進PHP成為一種流行的語言方面發揮了重要作用。


Zend Engine的出現將PHP程式碼的處理過程分成了兩個階段:首先是分析PHP程式碼並將其轉換為稱作Zend opcode的二進位制格式(類似Java的位元組碼),並將其儲存於記憶體中;第二階段是使用Zend Engine去執行這些轉換後的Opcode。


(3).PHP的Opcode

Opcode是一種PHP指令碼編譯後的中間語言,就像Java的ByteCode,或者.NET的MSL。PHP執行PHP指令碼程式碼一般會經過如下4個步驟(確切的來說,應該是PHP的語言引擎Zend):

  • Scanning(Lexing) —— 將PHP程式碼轉換為語言片段(Tokens)

  • Parsing —— 將Tokens轉換成簡單而有意義的表示式

  • Compilation —— 將表示式編譯成Opocdes

  • Execution —— 順次執行Opcodes,每次一條,從而實現PHP指令碼的功能


(4).PHP的加速器

基於PHP的特殊擴充套件機制如opcode快取擴充套件也可以將opcode快取於php的共享記憶體中,從而可以讓同一段程式碼的後續重複執行時跳過編譯階段以提高效能。由此也可以看出,這些加速器並非真正提高了opcode的執行速度,而僅是通過分析opcode後並將它們重新排列以達到快速執行的目的。

常見的php加速器有:

  • APC (Alternative PHP Cache) 遵循PHP License的開源框架,PHP opcode快取加速器,目前的版本不適用於PHP 5.4。專案地址,http://pecl.php.net/package/APC。

  • eAccelerator 源於Turck MMCache,早期的版本包含了一個PHP encoder和PHP loader,目前encoder已經不在支援。專案地址, http://eaccelerator.net/。

  • XCache 快速而且穩定的PHP opcode快取,經過嚴格測試且被大量用於生產環境。專案地址,http://xcache.lighttpd.net/

  • Zend Optimizer和Zend Guard Loader Zend Optimizer並非一個opcode加速器,它是由Zend Technologies為PHP5.2及以前的版本提供的一個免費、閉源的PHP擴充套件,其能夠執行由Zend Guard生成的加密的PHP程式碼或模糊程式碼。 而Zend Guard Loader則是專為PHP5.3提供的類似於Zend Optimizer功能的擴充套件。專案地址,http://www.zend.com/en/products/guard/runtime-decoders

  • NuSphere PhpExpress NuSphere的一款開源PHP加速器,它支援裝載通過NuSphere PHP Encoder編碼的PHP程式檔案,並能夠實現對常規PHP檔案的執行加速。專案地址,http://www.nusphere.com/products/phpexpress.htm


(5).PHP原始碼目錄結構

PHP的原始碼在結構上非常清晰。其程式碼根目錄中主要包含了一些說明檔案以及設計方案,並提供瞭如下子目錄:

  • build —— 顧名思義,這裡主要放置一些跟原始碼編譯相關的檔案,比如開始構建之前的buildconf指令碼及一些檢查環境的指令碼等。

  • ext —— 官方的擴充套件目錄,包括了絕大多數PHP的函式的定義和實現,如array系列,pdo系列,spl系列等函式的實現。 個人開發的擴充套件在測試時也可以放到這個目錄,以方便測試等。

  • main —— 這裡存放的就是PHP最為核心的檔案了,是實現PHP的基礎設施,這裡和Zend引擎不一樣,Zend引擎主要實現語言最核心的語言執行環境。

  • Zend —— Zend引擎的實現目錄,比如指令碼的詞法語法解析,opcode的執行以及擴充套件機制的實現等等。

  • pear —— PHP 擴充套件與應用倉庫,包含PEAR的核心檔案。

  • sapi —— 包含了各種伺服器抽象層的程式碼,例如apache的mod_php,cgi,fastcgi以及fpm等等介面。

  • TSRM —— PHP的執行緒安全是構建在TSRM庫之上的,PHP實現中常見的*G巨集通常是對TSRM的封裝,TSRM(Thread Safe Resource Manager)執行緒安全資源管理器。

  • tests —— PHP的測試指令碼集合,包含PHP各項功能的測試檔案。

  • win32 —— 這個目錄主要包括Windows平臺相關的一些實現,比如sokcet的實現在Windows下和*Nix平臺就不太一樣,同時也包括了Windows下編譯PHP相關的指令碼。

好了,說了這麼多PHP的相關知識我們就說到這吧。下面我們來說一說程式之間的跨平臺。


3.C/C++與Java

在說Java之間我們來得說一說,C與跨平臺的相關知識。我們都知道C語言是物件導向的語言,C++是物件導向的語言。相對於PHP語言來說C語言或者C++語言,更接近底層的語言或者說更接近於硬體。執行效率要比PHP這種解釋型語言高的多。那大家想啊,我們經常用PHP來編寫Web應用,那我們能不能用C語言來編寫網站呢。答案是否定的,因為沒有一家公司要C語言來開發網站的,大家都知道我們編寫C語言都先編寫後進行編譯,然後再執行。那大家想啊,我們網站變動很快,幾乎每天都的大量的更新,每次更新都要進行編譯,然後再執行。維護成本太高了,就算是有公司出的起成本,也沒有公司會用,C語言還有個致命的弱點那就是不能跨平臺,比如我們的網站是在32位平臺上開發的,那我們只能在32位平臺上執行,而不能在64位平臺上執行。所以用C語言編寫的網站移植會很困難。剛才我們說到了跨平臺,下面我們就說一下與平臺相關的問題。


大家都知道,用C語言我們一般用來開發作業系統,而不是來用編寫網站的。現在主流的作業系統有兩種,一種是Windows系統,另一種是Linux系統。我們大家又知道,用C語言的作業系統都是有API介面(Application Programming Interface)的,簡單來說API就是系統呼叫。幫助我們的開發人員更好的開發應用軟體,由於作業系統的不同API又分為Windows API和Linux API。我們在Windows平臺開發出來的軟體在Linux上無法執行,在Linux上開發的軟體在Windows上又無法執行,這就導致了軟體移植困難,我們開發軟要開發兩份,甚至更多版本很是煩鎖。後大家就規定一個統一的API介面即POSIX(Protabl Operation System 可移植作業系統規範)。


但是我們知道一個應用程式的執行,需要諸多相關的庫檔案來支撐的。在Windows當中的庫檔案是*.dll(動態連結庫)而Linux當中的庫檔案是*.so(共享物件)。這樣編寫的程式,也是不能跨平臺的。後來為了解決這個問題就提出是ABI介面(Application Binary Interface 應用程式二進位制介面)。好了,我們說了這麼多,其實就想表達兩個意思。一是C語言是不能用來編寫網站的,二是C語言移植困難、維護成本高。下面我們就來說一說Java。


二、Java

1.Java 簡介

Java是由Sun Microsystems公司於 1995年5月推出的Java物件導向程式設計語言(以下簡稱Java語言)和Java平臺的總稱。由James Gosling和同事們共同研發,並在1995年正式推出。用Java實現的HotJava瀏覽器(支援Java applet)顯示了Java的魅力:跨平臺、動態的Web、Internet計算。從此,Java被廣泛接受並推動了Web的迅速發展,常用的瀏覽器均支援Javaapplet。另一方面,Java技術也不斷更新。(2010年Oracle公司收購了SUN)


2.Java 組成

Java由四方面組成:

  • Java程式語言

  • Java類檔案格式

  • Java虛擬機器

  • Java應用程式介面(Java API)

下面我們來說一下這四個方面的關係,我們通過Java程式語言+Java應用程式介面(Java API)編寫出*.java的檔案(如,test.java),通過Java編譯器javac(Java Complier)進行編譯生成*.class的類檔案(如,test.class),再通過Java類檔案+Java虛擬機器(JVM)執行Java程式。簡單過程如下,

  • Java 程式語言+Java API —> test.java (java程式)

  • javac(Java Complier) —> test.class (位元組碼檔案)

  • Java類檔案+Java虛擬機器 —> 執行test.class

效果1

好了,下面我們來說一說,Java虛擬機器(JVM)的組成。

JVM 組成:

  • JRE(JVM+Java SE API),是用於實現Java程式執行的最小環境。

  • JDK (Java+API+JVM),是用於實現Java程式開發的最小環境。


3.Java 平臺

Java平臺由Java虛擬機器(Java Virtual Machine,簡稱JVM)和Java 應用程式設計介面(Application Programming Interface,簡稱API)構成。Java應用程式設計介面為此提供了一個獨立於作業系統的標準介面,可分為基本部分和擴充套件部分。在硬體或作業系統平臺上安裝一個Java平臺之後,Java應用程式就可執行。Java平臺已經嵌入了幾乎所有的作業系統。這樣Java程式可以只編譯一次,就可以在各種系統中執行。Java應用程式設計介面已經從1.1x版發展到1.2版。常用的Java平臺基於Java1.5,最近版本為Java7.0。

2

4.Java 體系

Java分為三個體系,

  • J2SE(Java2 Platform Standard Edition,java平臺標準版)

  • J2EE(Java 2 Platform,Enterprise Edition,java平臺企業版)

  • J2ME(Java 2 Platform Micro Edition,java平臺微型版)。

其中,Java SE則只包含了Java二進位制程式(如JVM和Java位元組碼編譯器)和Java的核心程式碼庫,而Jave EE標準則包含了一組適用於建立企業級Web應用程式的API。Jave EE建立在Java SE的基礎上,並依賴於Java SE才能正常工作。當然,任何級別的應用程式均能從Java EE中獲益,但Jave EE卻更適合解決大型軟體系統設計中的問題。JAVA EE包含多個獨立的API,Servlet和JSP就是其中的兩個,而JAVA EE中著名的API中還包含如下的幾個,

JAVA EE APIs:

  • EJB(Enterprise JavaBeans):JAVA相關的諸多高階功能的實現,如RMI(Remote Method Invocation), 物件/關係對映,跨越多個資料來源的分散式事務等;

  • JMS(Java Message Service):高效能非同步訊息服務,實現JAVA EE應用程式與非JAVA程式的“透明”通訊;

  • JMX(Java Management Extensions):在程式執行時對其進行互動式監控和管理的機制;

  • JTA(Java Transaction API):允許應用程式在自身的一個或多個元件中平滑地處理錯誤的機制;

  • JavaMail:通過工業標準的POP/SMTP/IMAP協議傳送和接收郵件的機制;

Java SE APIs:

  • JNDI(Java Naming and Directory Interface):用於與LDAP服務互動的API;

  • JAXP(Java API for XML Processing):用於分析及轉換XML(基於XSLT實現);


5.Java 優勢

與傳統程式不同,Sun 公司在推出 Java 之際就將其作為一種開放的技術。全球數以萬計的 Java 開發公司被要求所設計的 Java軟體必須相互相容。“Java 語言靠群體的力量而非公司的力量”是Sun公司的口號之一,並獲得了廣大軟體開發商的認同。這與微軟公司所倡導的注重精英和封閉式的模式完全不同。Sun 公司對 Java 程式語言的解釋是:Java 程式語言是個簡單、物件導向、分散式、解釋性、健壯、安全與系統無關、可移植、高效能、多執行緒和動態的語言。Java 平臺是基於 Java 語言的平臺。這樣的平臺非常流行。因此微軟公司推出了與之競爭的.NET平臺以及模仿Java的C#語言。


6.Java 執行過程

3

用Java語言來編寫原始碼,把它編譯成Java Class檔案,然後在Java VM中執行class檔案;當編寫程式時,通過呼叫類(Java API)中的方法來訪問系統資源,而當程式執行時,它通過呼叫class檔案中實現了Java API的方法也滿足程式的Java API呼叫。Java VM和Java API一起組成了一個“平臺“,所有Java程式都在其上編譯和執行,因此,它們有時也被稱作Java執行時環境。Java VM的主要任務是裝載class檔案並且執行其中的位元組碼。Java VM包含一個類裝載器(class loader),它可以從程式和API裝載class檔案;而Java API的類只在程式執行中需要時才會被裝載。(如上圖)


Java位元組碼由執行引擎來執行。而不同的Java VM中,其執行引擎的實現可能各不相同。最簡單的執行引擎不是一次性解釋位元組碼,而另一種稱為“即時編譯器(just-in-time compiler)”的執行引擎執行速度更快,但要消耗更多的記憶體資源。即時編譯模式下,第一次被執行的位元組碼會被編譯成本地機器程式碼並快取下來以實現“複用”。第三種執行引擎是所謂的自適應優化器,此種方法中,虛擬機器始的時候解釋位元組碼,介是會監視執行中程式的活動,並且記錄下使用最頻繁的程式碼。程式執行時,虛擬機器只把那些活動最頻繁的程式碼編譯成原生程式碼,而不頻繁的程式碼則仍然保留為位元組碼由虛擬機器解釋執行。自適應優化器可以使得Java VM在80%-90%的時間裡執行被優化過的原生程式碼,而只需要編譯10%- 20%對效能有影響的程式碼。最後一種虛擬機器由硬體晶片構成,它用本地方法執行Java位元組碼,其執行引擎內嵌於晶片中。


三、Servlet與JSP

1. Servlet是什麼?

在Client/Server應用的發展過程中,Java提供了一整套Client/Server解決方案,在這個方案中,程式可以自動地下載到客戶端並執行,這就是applet。但是它僅僅是問題的一半,問題的另一半就是Servlet。Servlet可以被認為是伺服器端的applet。Servlet被Web伺服器載入和執行,就如同applet被瀏覽器載入和執行一樣。Servlet從客戶端(通過Web伺服器)接收請求,執行某種作業,然後返回結果。使用servlet的基本流程如下:

  • 客戶端通過HTTP提出請求。

  • Web伺服器接收該請求並將其發給Servlet。如果這個Servlet尚未被載入,Web伺服器將把它載入到Java虛擬機器並且執行它。

  • Servlet將接收該HTTP請求並執行某種處理。

  • Servlet將向Web伺服器返回應答。

  • Web伺服器將從Servlet收到的應答傳送給客戶端。

由於servlet是在伺服器上執行,通常與applet相關的安全性的問題並不需實現。要注意的是Web瀏覽器並不直接和Servlet通訊,Servlet是由Web伺服器載入和執行的。而Servlet是用Java編寫的,所以它們一開始就是平臺無關的。這樣,Java編寫一次就可以在任何平臺執行(write once,run anywhere)的承諾就同樣可以在伺服器上實現了。Servlet還有一些CGI指令碼所不具備的獨特優點:

  • Servlet是持久的。Servlet只需Web伺服器載入一次,而且可以在不同請求之間保持服務(例如一次資料庫連線)。與之相反,CGI指令碼是短暫的、瞬態的。每一次對CGI指令碼的請求,都會使Web伺服器載入並執行該指令碼。一旦這個CGI指令碼執行結束,它就會被從記憶體中清除,然後將結果返回到客戶端。CGI指令碼的每一次使用,都會造成程式初始化過程(例如連線資料庫)的重複執行。

  • Servlet是與平臺無關的。如前所述,servlet是用Java編寫的,它自然也繼承了Java的平臺無關性。

  • Servlet是可擴充套件的。由於servlet是用Java編寫的,它就具備了Java所能帶來的所有優點。Java是健壯的、物件導向的程式語言,它很容易擴充套件以適應你的需求。servlet自然也具備了這些特徵。

  • Servlet是安全的。從外界呼叫一個servlet的惟一方法就是通過Web伺服器。這提供了高水平的安全性保障,尤其是在你的Web伺服器有防火牆保護的時候。

Setvlet可以在多種多樣的客戶機上使用。由於Servlet是用Java編寫的,所以你可以很方便地在HTML中使用它們,就像你使用applet一樣。那麼,Servlet是怎樣執行的?怎樣來寫一個Servlet,它的基本架構是怎麼樣的?這些問題,將在後面部分給予介紹。


2.JSP與Servlet

現在已經對Servlet有了大概的瞭解,現在我們就來說說JSP和Servlet的關係。

JSP是一種指令碼語言,包裝了Java Servlet系統的介面,簡化了Java和Servlet的使用難度,同時通過擴充套件JSP標籤(TAG)提供了網頁動態執行的能力。儘管如此,JSP仍沒有超出Java和Servlet的範圍,不僅JSP頁面上可以直接寫Java程式碼,而且JSP是先被譯成Servlet之後才實際執行的。JSP在伺服器上執行,並將執行結果輸出到客戶端瀏覽器,我們可以說基本上與瀏覽器無關。它是與JavaScript不同的,JavaScript是在客戶端的指令碼語言,在客戶端執行,與伺服器無關。那麼JSP是什麼?就是Servlet。


JSP與Servlet之間的主要差異在於,JSP提供了一套簡單的標籤,和HTML融合的比較好,可以使不瞭解Servlet的人可以做出動態網頁來。對於Java語言不熟悉的人(比如像我),會覺得JSP開發比較方便。JSP修改後可以立即看到結果,不需要手工編譯,JSP引擎會來做這些工作;而Servelt還需要編譯,重新啟動Servlet引擎等一系列動作。但是在JSP中,HTML與程式程式碼混雜在一起,而Servlet卻不是這樣。也許大家比較混亂了,那麼Servlet又是什麼?下面我們對JSP的執行來做一個簡單的介紹,告訴大家怎樣來執行一個JSP檔案:

當Web伺服器(或Servlet引擎,應用伺服器)支援JSP引擎時,JSP引擎會照著JSP的語法,將JSP檔案轉換成Servlet程式碼原始檔,接著Servlet會被編譯成Java可執行位元組碼(bytecode),並以一般的Servlet方式載入執行。簡單來說就是,*.jsp檔案 -jasper引擎-> *.java檔案 -javac編譯器-> .class (JVM執行)。


JSP語法簡單,可以方便的嵌入HTML之中,很容易加入動態的部分,方便的輸出HTML。在Servlet中輸出HTML則需要呼叫特定的方法,對於引號之類的字元也要做特殊的處理,加在複雜的HTML頁面中作為動態部分,比起JSP來說是比較困難的。除去了轉換和編譯階段,JSP和Servlet之間的區別實在是不大。


JSP引擎通常架構在Servlet引擎之上,本身就是一個Servlet,把JSP檔案轉譯成Servlet原始碼,再呼叫Java編譯器,編譯成Servlet。這也是JSP在第一次呼叫時速度比較慢的原因,在第一次編譯之後,JSP與Servlet速度相同。下面我們來看看為什麼他們在第一次編譯後再編譯的速度相同。


在整個執行過程中,JSP引擎會檢查編譯好的JSP(以Servlet形式存在)是否比原始的JSP檔案還新。如果是,JSP引擎不會編譯;如果不是,表示JSP檔案比較新,就會重新執行轉譯與編譯的過程。為了有個深刻的瞭解,我們看一下JSP的執行和開發環境:

  • 瀏覽器:常見的瀏覽器有IE和火狐等。

  • 據庫:常用的資料庫有Oracle,SQL Server,Informix,DB2,Sybase,Access,MySQL等。

  • 作業系統:常見的有Windows,Linux,以及各種Unix系統。

  • Web伺服器:常見的有IIS,Apache,Netscape Enterprise Server等。

  • JSP引擎:一般JSP引擎都以Servlet引擎為基礎,並以Servlet的形式出現。同時,在各種免費和商業引擎的實現中,Servlet引擎和JSP引擎通常也是一起出現,我們成為Servlet/JSP引擎,或從某種成為JSP引擎。JSP引擎是可以提供JSP和Servlet執行支援並對其生存週期進行管理的系統級實體。


在JSP頁面第一次被請求時,JSP引擎會將JSP原始檔案轉換成Servlet原始碼,然後呼叫Java編譯器,編譯成Servlet並在Servlet引擎中執行。當再次有請求的時候,JSP引擎會見差異編譯好的JSP是否比原來的JSP原始檔案要新。如果是,則執行Servlet;如果不是,表示檔案已經更新的了,就會從新執行轉換和編譯的過程。


說到這裡,也基本把JSP和Servlet的關係說清楚了,從我的感覺上看用JSP就可以了,簡單又方便,又可以和Bean很好的相容使用,功能又很強大,為什麼又出現了Servlet,它又有什麼用?何況它的編寫又相對複雜。為了把問題說得更清楚一點,我想在這裡說一下歷史,順便再講一下為什麼還要用Servlet,Servlet的好處是什麼?


簡單的說,SUN首先發展出Servlet,其功能比較強勁,體系設計也很先進。只是,它輸出HTML語句還是採用了老的CGI方式,是一句一句輸出。所以,編寫和修改HTML非常不方便。後來SUN推出了類似於ASP的嵌入式的JSP(是Servlet發展的產物),把JSP TAG嵌入到HTML語句中,這樣,就大大簡化和方便了網頁的設計和修改。新型的網路語言如ASP,PHP,JSP都是嵌入型的SCRIPT語言。


從Web三層結構的角度看,一個Web專案最少分三層:data layer(資料層),business layer(業務層), presentation layer(展示層)。當然也可以更復雜。S用來寫business layer是很強大的,但是對於寫presentation layer就很不方便。JSP則主要是為了方便寫presentation layer而設計的。當然也可以寫business layer。寫慣了ASP,PHP,CGI的朋友,經常會不自覺的把presentation layer和business layer混在一起。把資料庫處理資訊放到JSP中,其實,它應該放在business layer中。


根據SUN自己的推薦,JSP中應該僅僅存放與presentation layer有關的內容,也就是說,只放輸出HTML網頁的部份。而所有的資料計算,資料分析,資料庫聯結處理,統統是屬於business layer,應該放在JAVA BEANS中。通過JSP呼叫JAVA BEANS,實現兩層的整合。


實際上,微軟推出的DNA技術,簡單說,就是ASP+COM/DCOM技術。與JSP+BEANS完全類似,所有的presentation layer由ASP完成,所有的business layer由COM/DCOM完成。通過呼叫,實現整合。現在微軟推出的.NET也是通過這個理念,所有的presentation layer由ASP.NET完成,business layer由C#或VB.NET或VC.NET來完成。


為什麼要採用這些元件技術呢?因為單純的ASP/JSP語言是非常低效率執行的,如果出現大量使用者點選,純SCRIPT語言很快就到達了他的功能上限,而元件技術就能大幅度提高功能上限,加快執行速度。另外一方面,純SCRIPT語言將presentation layer和business layer混在一起,造成修改不方便,並且程式碼不能重複利用。如果想修改一個地方,經常會牽涉到十幾頁code,採用元件技術就只改元件就可以了。


綜上所述,Servlet是一個早期的不完善的產品,寫business layer很好,寫presentation layer就很不好,並且兩層混雜,顯得十分混亂。所以,推出JSP+BAEN,用JSP寫presentation layer,用BAEN寫business layer。SUN自己的意思也是將來用JSP替代Servlet。


看了上面的敘述,大家可能對JSP與Servlet共存有了比較好的認識。可以看到JSP和Bean結合後的的實用性,強大的表現功能,易用性都是Servlet所不能及的。那麼是不是Servlet就被取代了?不是!在以後的發展中,它還是有著巨大的作用的。上面只不過是將了問題的一方面,下面我們來看看Servlet本身的特點。由於它是由java來寫的,所以相關的特點我們就不說了,上文已經有了詳細的介紹,我們來看看其他的特點,Servlet是用於開發伺服器端應用程式的一種程式設計模型,如果只是一個普通的java應用,可以不使用Servlet來編寫,但是如果想要提供基於web的服務能力,那麼就必須按照這種模型來編寫,而且Servlet也必須允許在符合Servlet規範的java web server or app server之上,否則無法執行。除非你自己實現一個Web server,但是其複雜度是比較高的,特別是在企業級應用中,對系統的穩定性和健壯性都要求比較高,所以Servlet的模型實際上是簡化了編寫穩健的伺服器端的應用開發過程。Servlet 可以作為提供web服務能力的一個接入方式,現在也許可以理解了什麼是Servlet什麼是JSP,它們之間的關係是怎樣的。好了,知識鋪墊我們就說到這了。我已經盡最大的努力來說明Servlet與JSP了,畢竟我不是開發啊。想深入瞭解JSP與Servlet的朋友可以可以看看Java Web開發的相關書箱。下面我們來說一說JSP執行過程。


3.JSP 運程過程

一個JSP頁面有多個客戶訪問,下面是第一個客戶訪問JSP頁面時候,JSP頁面的執行流程:

  • 客戶通過瀏覽器向伺服器端的JSP頁面傳送請求

  • JSP引擎檢查JSP檔案對應的Servlet原始碼是否存在,若不存在轉向第4步,否則執行下一步

  • JSP引擎檢查JSP頁面是否需要修改,若沒修改,轉向第5步,否則執行下一步

  • JSP引擎將JSP頁面檔案轉譯為Servlet原始碼(相應的 .java 程式碼)

  • JSP引擎將Servlet原始碼編譯為相應位元組碼( .class程式碼 )

  • JSP引擎載入位元組碼到記憶體

  • 位元組碼處理客戶請求,並將結果返回給客戶

JSP響應過程

在不修改JSP頁面的情況下,除了第一個客戶訪問JSP頁面需要經過以上幾個步驟外,以後訪問該JSP頁面的客戶請求,直接傳送給JSP對應的位元組碼程式處理,並將處理結果返回給客戶,這種情況下,JSP頁面既不需要啟動伺服器,以便重新載入修改後的JSP頁面。


四、Tomcat

1.概述

通過上面的講解大家對JSP與Servlet已經有所理解,最起碼知道它們是做什麼的,說到底它們都是程式設計語言,是幫助我們更好的編寫程式。大家都知道,不管是Servlet也好,還是JSP也好它們編寫出來的應用程式都是要執行的。在Web伺服器的支援下可以執行解析並且執行,最終能被使用者所看到並操作,這是才我們的最終目的。那能實現對JSP與Servlet解析並執行的Web伺服器有哪些呢?(注,我們一般說能解析並執行JSP與Servlet的程式為Web伺服器,可在JSP與Servlet這裡我們稱為Web容器。在下面的內容中我們就說Web容器,也就是Web伺服器)


2.常見的web容器

商業版:

  • Sun GlassFish Enterprise Server

  • Sun Java System Web Server

  • JBoss Enterprise Application Platform

  • WebLogic Application Server

  • Caucho`s Resin Server

  • WebSphere Application Server

  • NetWeaver

非商業版:

  • Apache Tomcat

  • Apache Geronimo

  • GlassFish

  • JBoss Application Server

  • Jetty

  • Tiny Java Web Server

  • Eclipse Virgo

注,用的最多的不是Tomcat,我們這裡主要講解tomcat。


3.Tomcat 簡介

Sun推出的JSP(Java Server Pages)是一種執行於伺服器端的動態網頁開發技術,它基於Java技術。執行JSP時需要在Web伺服器上架設一個編譯JSP網頁的引擎。Tomcat伺服器是Apache組織開發的一種JSP引擎同時支援Servlet,本身具有Web伺服器的功能,可以作為獨立的Web伺服器來使用。但是,在作為Web伺服器方面,Tomcat處理靜態HTML頁面時不如Apache迅速,也沒有Apache健壯,所以我們一般將Tomcat與Apache配合使用,讓Apache對網站的靜態頁面請求提供服務,而Tomcat作為專用的JSP引擎,提供JSP解析,以得到更好的效能。並且Tomcat本身就是Apache的一個子專案,所以Tomcat對Apache提供了強有力的支援。對於大多數網站來說,Tomcat是一個很不錯的選擇


Tomcat 在嚴格意義上並不是一個真正的應用伺服器,它只是一個可以支援執行Serlvet/JSP的Web容器,不過Tomcat也擴充套件了一些應用伺服器的功能,如JNDI,資料庫連線池,使用者事務處理等等。Tomcat 是一種具有JSP環境的Servlet容器。Servlet容器是代替使用者管理和呼叫 Servlet的執行時外殼。那麼什麼是Servlet容器呢?


Servlet容器,負責處理客戶請求。當客戶請求來到時,Servlet容器獲取請求,然後呼叫某個Servlet,並把Servlet的執行結果返回給客戶。當客戶請求某個資源時,Servlet容器使SERVLETREQUEST物件把客戶的請求資訊封裝起來,然後呼叫JAVA Servlet API中定義的Servlet的一些生命週期方法,完成Servlet的執行,接著把Servlet執行的要返回給客戶的結果封裝到SERVLETRESPONSE物件中,最後SERVLET容器把客戶的請求傳送給客戶,完成為客戶的一次服務過程。


4.Tomcat 體系結構

tomcat news

Tomcat 支援Servlet 2.5和JSP 2.1的規範,它由一組巢狀的層次和元件組成,一般可分為以下四類:

  • 頂級元件:位於配置層次的頂級,並且彼此間有著嚴格的對應關係(如,Server、Service);

  • 聯結器:連線客戶端(可以是瀏覽器或Web伺服器)請求至Servlet容器,

  • 容器:包含一組其它元件,如Engine、Host、Content;

  • 被巢狀的元件:位於一個容器當中,但不能包含其它元件(如,Realm(使用者賬戶資料庫)、valve(基於使用者的認證)、logger(記錄日誌));


頂級元件:

(1).伺服器(server):Tomcat的一個例項,通常一個JVM只能包含一個Tomcat例項;因此,一臺物理伺服器上可以在啟動多個JVM的情況下在每一個JVM中啟動一個Tomcat例項,每個例項分屬於一個獨立的管理埠。這是一個頂級元件。


(2).服務(service):一個服務元件通常包含一個引擎和與此引擎相關聯的一個或多個聯結器。給服務命名可以方便管理員在日誌檔案中識別不同服務產生的日誌。一個server可以包含多個service元件,但通常情下只為一個service指派一個server。


聯結器類元件:

聯結器(connectors):負責連線客戶端(可以是瀏覽器或Web伺服器)請求至Servlet容器內的Web應用程式,通常指的是接收客戶發來請求的位置及伺服器端分配的埠。預設埠通常是HTTP協議的8080,管理員也可以根據自己的需要改變此埠。一個引擎可以配置多個聯結器,但這些聯結器必須使用不同的埠。預設的聯結器是基於HTTP/1.1的Coyote。同時,Tomcat也支援AJP、JServ和JK2聯結器。


容器類元件:

(1).引擎(Engine):引擎通是指處理請求的Servlet引擎元件,即Catalina Servlet引擎,它檢查每一個請求的HTTP首部資訊以辨別此請求應該發往哪個host或context,並將請求處理後的結果返回的相應的客戶端。嚴格意義上來說,容器不必非得通過引擎來實現,它也可以是隻是一個容器。如果Tomcat被配置成為獨立伺服器,預設引擎就是已經定義好的引擎。而如果Tomcat被配置為Apache Web伺服器的提供Servlet功能的後端,預設引擎將被忽略,因為Web伺服器自身就能確定將使用者請求發往何處。一個引擎可以包含多個host元件。

(2).主機(Host):主機元件類似於Apache中的虛擬主機,但在Tomcat中只支援基於FQDN的“虛擬主機”。一個引擎至少要包含一個主機元件。

(3).上下文(Context):Context元件是最內層次的元件,它表示Web應用程式本身。配置一個Context最主要的是指定Web應用程式的根目錄,以便Servlet容器能夠將使用者請求發往正確的位置。Context元件也可包含自定義的錯誤頁,以實現在使用者訪問發生錯誤時提供友好的提示資訊。


被巢狀類(nested)元件:

這類元件通常包含於容器類元件中以提供具有管理功能的服務,它們不能包含其它元件,但有些卻可以由不同層次的容器各自配置。 

(1).閥門(Valve):用來攔截請求並在將其轉至目標之前進行某種處理操作,類似於Servlet規範中定義的過濾器。Valve可以定義在任何容器類的元件中。Valve常被用來記錄客戶端請求、客戶端IP地址和伺服器等資訊,這種處理技術通常被稱作請求轉儲(request dumping)。請求轉儲valve記錄請求客戶端請求資料包中的HTTP首部資訊和cookie資訊檔案中,響應轉儲valve則記錄響應資料包首部資訊和cookie資訊至檔案中。 

(2).日誌記錄器(Logger):用於記錄元件內部的狀態資訊,可被用於除Context之外的任何容器中。日誌記錄的功能可被繼承,因此,一個引擎級別的Logger將會記錄引擎內部所有元件相關的資訊,除非某內部元件定義了自己的Logger元件。 

(3).領域(Realm):用於使用者的認證和授權;在配置一個應用程式時,管理員可以為每個資源或資源組定義角色及許可權,而這些訪問控制功能的生效需要通過Realm來實現。Realm的認證可以基於文字檔案、資料庫表、LDAP服務等來實現。Realm的效用會遍及整個引擎或頂級容器,因此,一個容器內的所有應用程式將共享使用者資源。同時,Realm可以被其所在元件的子元件繼承,也可以被子元件中定義的Realm所覆蓋。


引擎(Engine):引擎是指處理請求的Servlet引擎元件,即Catalina Servlet引擎,它從HTTPconnector接收請求並響應請求。它檢查每一個請求的HTTP首部資訊以辨別此請求應該發往哪個host或context,並將請求處理後的結果返回的相應的客戶端。嚴格意義上來說,容器不必非得通過引擎來實現,它也可以是隻是一個容器。如果Tomcat被配置成為獨立伺服器,預設引擎就是已經定義好的引擎。而如果Tomcat被配置為Apache Web伺服器的提供Servlet功能的後端,預設引擎將被忽略,因為Web伺服器自身就能確定將使用者請求發往何處。一個引擎可以包含多個host元件。


Tomcat聯結器架構:基於Apache做為Tomcat前端的架構來講,Apache通過mod_jk、mod_jk2或mod_proxy模組與後端的Tomcat進行資料交換。而對Tomcat來說,每個Web容器例項都有一個Java語言開發的聯結器模組元件,在Tomcat中,這個聯結器是org.apache.catalina.Connector類。這個類的構造器可以構造兩種類別的聯結器:HTTP/1.1負責響應基於HTTP/HTTPS協議的請求,AJP/1.3負責響應基於AJP的請求。但可以簡單地通過在server.xml配置檔案中實現聯結器的建立,但建立時所使用的類根據系統是支援APR(Apache Portable Runtime)而有所不同。APR是附加在提供了通用和標準API的作業系統之上一個通訊層的本地庫的集合,它能夠為使用了APR的應用程式在與Apache通訊時提供較好伸縮能力時帶去平衡效用。同時,需要說明的是,mod_jk2模組目前已經不再被支援了,mod_jk模組目前還apache被支援,但其專案活躍度已經大大降低。因此,目前更常用 的方式是使用mod_proxy模組。

如果支援APR:

  • HTTP/1.1:org.apache.cotote.http11.Http11AprProtocol

  • AJP/1.3:org.apache.coyote.ajp.AjpAprProtocol

如果不支援APR:

  • HTTP/1.1: org.apache.coyote.http11.Http11Protocol

  • AJP/1.3: org.apache.jk.server.JkCoyoteHandler


聯結器協議:

Tomcat的Web伺服器聯結器支援兩種協議:AJP和HTTP,它們均定義了以二進位制格式在Web伺服器和Tomcat之間進行資料傳輸,並提供相應的控制命令。

AJP(Apache JServ Protocol)協議:目前正在使用的AJP協議的版本是通過JK和JK2聯結器提供支援的AJP13,它基於二進位制的格式在Web伺服器和Tomcat之間傳輸資料,而此前的版本AJP10和AJP11則使用文字格式傳輸資料。

HTTP協議:誠如其名稱所表示,其是使用HTTP或HTTPS協議在Web伺服器和Tomcat之間建立通訊,此時,Tomcat就是一個完全功能的HTTP伺服器,它需要監聽在某埠上以接收來自於商前伺服器的請求。


5.Tomcat 工作模式

(1).獨立的Servlet容器

Tomcat 的預設工作模式,作為獨立的Servlet容器,是內建在Web伺服器中的一部分,是指使用基於JAVA的Web伺服器的情形。其他兩種方式是TOMCAT與其他伺服器整合的方式。

(2).程式內的Servlet容器

Servlet容器作為Web伺服器的外掛和JAVA容器的實現。Web伺服器的外掛在內部地址空間開啟一個JVM(JAVA VIRTUAL MACHINE)使JAVA容器得以在內部執行。如有某個需要呼叫Servlet的請求,外掛將取得對此請求的控制並將它傳遞(使用JNI)給JAVA容器。程式內的容器對於多執行緒、單程式的伺服器非常適合,並且提供了很好的執行速度,只是伸縮性有所不足。

注,JNI是JAVA NATIVE INTERFACE的縮寫,是JAVA本地呼叫介面,通過JNI,JAVA程式可以和其他語言編寫的本地程式進行通訊。

(3).程式外的Servlet容器

Servlet容器執行於Web伺服器之外的地址空間,並且作為Web伺服器的外掛和JVM使用IPC(如TCP/IP)進行通訊。程式外容器的反應時間不如程式內的容器,但有較好的伸縮性、穩定性等效能。

IPC INTERPROCESS COMMUNICATION(程式間通訊)的簡寫,它是實現程式間通訊的一種技術。


6.Tomcat 的組織結構

Tomcat是一個基於元件的伺服器,它的構成元件都是可配置的,其中最外層的給件是CATALINA SERVLET容器,其他的元件按照一定的格式要求配置在這個頂層容器中。Tomcat的各個元件是server.xml檔案中配置的,Tomcat伺服器預設情況下對各種元件都有預設的實現,下面通過分析server.xml檔案來理解Tomcat的各個元件是如何組織的。

1
2
3
4
5
6
7
8
9
10
11
<Server>      頂層元素,代表一個伺服器
  <Service>  頂層元素,是Connector的集合,只有一個Engine
      <Connectior/>        聯結器類元素,代表通訊介面
          <Engine>   容器類元素,為特定的Service元件處理所有客戶請求,可包含多個Host
              <Host>    為特定的虛擬主機處理所有客戶請求
                  <Context>     為特定的WEB應用處理所有客戶請求
                  </Context>
              </Host>
          </Engine>
</Service>
</Server>

Tomcat中真正處理客戶請求與生成響應的三個元件是Engine 、Host、 Context。為了幫助大家更好的理解Tomcat的組織結構,請看下圖:

tomcat 組織

好了,說到這裡有關Tomcat的相關理論知識我們就講的差不多了,在下面的一篇部落格中我們將講解Tomcat的安裝與配置。希望大家有所收^_^……


















本文轉自陳明乾51CTO部落格,原文連結:http://blog.51cto.com/freeloda/1298687,如需轉載請自行聯絡原作者










相關文章