日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

《深入剖析Tomcat》一2.2 应用程序 1

發(fā)布時間:2025/3/18 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 《深入剖析Tomcat》一2.2 应用程序 1 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2.2 應用程序 1

下面從servlet容器的角度審視servlet程序的開發(fā)。簡單來說,對一個Servlet的每個HTTP請求,一個功能齊全的servlet容器有以下幾件事要做:
當第一次調用某個servlet時,要載入該servlet類,并調用其init()方法(僅此一次);
針對每個request請求,創(chuàng)建一個javax.servlet.ServletRequest實例和一個javax.servlet.ServletResponse實例;
調用該servlet的service()方法,將servletRequest對象和servletResponse對象作為參數傳入;
當關閉該servlet類時,調用其destroy()方法,并卸載該servlet類。
本章所要建立的servlet容器是一個很小的容器,沒有實現所有的功能。因此,它只能運行非常簡單的servlet,而且也會不調用servlet的init()和destroy()方法。它會做以下幾件事:
等待HTTP請求;
創(chuàng)建一個servletRequest對象和一個servletResponse對象;
若請求的是一個靜態(tài)資源,則調用StaticResourceProcessor對象的process()方法,傳入servletRequest對象和servletResponse對象;
若請求的是servlet,則載入相應的servlet類,調用其service()方法,傳入servletRequest對象和servletResponse對象。
注意 在該servlet容器中,每次請求servlet都會載入相應的servlet類。
本節(jié)的應用程序包括6個類:
HttpServer1
Request
Response
StaticResourceProcessor
ServletProcessor1
Constants
圖2-1展示了本節(jié)中的servlet容器的UML類圖。
該應用程序的入口點(靜態(tài)main()方法)在類HttpServer1中。main()方法創(chuàng)建HttpServer1的一個實例,然后調用其await()方法。await()方法會等待HTTP請求,為接收到的每個請求創(chuàng)建一個Request和一個Response對象,并根據該HTTP請求的是靜態(tài)資源或是servlet,將該HTTP請求分發(fā)給一個StaticResourceProcessor實例或一個ServletProcessor實例。
Constants類中定義了靜態(tài)final WEB_ROOT,供其他的類引用。WEB_ROOT指定了該servlet容器中使用的PrimitiveServlet類和靜態(tài)資源的位置。
HttpServer1類的實例會一直等待HTTP請求,直到接收到一條關閉命令。可以使用第1章介紹的方法來發(fā)布關閉命令。
該應用程序中的各個類會在接下來的幾節(jié)中逐個說明。

2.2.1 HttpServer1類

應用程序1中的HttpServer1類與第1章中簡單Web服務器應用程序中的HttpServer類似。但是,該應用程序中的HttpServer1類既可以對靜態(tài)資源請求,也可以對于servlet資源請求。若要請求一個靜態(tài)資源,可以在瀏覽器的地址欄或URL框中輸入如下格式的URL:

http://machineName:port/staticResource

這與第1章的Web服務器應用程序中對靜態(tài)資源的請求相同。
若要請求servlet資源,可以使用如下格式的URL:

http://machineName:port/servlet/servletClass

因此,若要請求本地瀏覽器上的名為PrimitiveServlet的servlet,可以在瀏覽器的地址欄或URL框中輸入如下的URL:

http://localhost:8080/servlet/Primitiveservlet

應用程序1中的servlet容器會處理對PrimitiveServlet的請求。但是,若要調用其他的servlet(如ModernServlet),則servlet容器拋出異常。在后面的章節(jié)中,你將學會如何構建可以兼具兩種功能的servlet容器。
HttpServer1類的定義在代碼清單2-2中。



該類的await()方法會一直等待HTTP請求,直到接收到一條關閉命令,這點與第1章中的await()方法類似。區(qū)別在于,本章中的await()方法可以將HTTP請求分發(fā)給StaticResourceProcessor對象或ServletProcessor對象來處理。當URI包含字符串“/servlet/”時,會把請求轉發(fā)給servletProcessor對象處理。否則的話,把HTTP請求傳遞給StaticResourceProcessor對象處理。注意代碼清單2-2中灰色的部分。

2.2.2 Request類

servlet的service方法會從servlet容器中接收一個javax.servlet.ServletRequest實例一個和javax.servlet.ServletResponse實例。即,對每個HTTP請求來說,servlet容器必須創(chuàng)建一個ServletRequest對象和一個ServletResponse對象,并將它們作為參數傳給它服務的servlet的service()方法。
ex02.pyrmont.Request類表示被傳遞給servlet的service()方法的一個request對象。它必須實現javax.Servlet.servletRequest接口中聲明的所有方法。但為了簡單起見,這里只給出了部分方法的實現,其余方法的實現會在后面的章節(jié)給出。為了能夠編譯Request類,需要將未實現的方法留空。代碼清單2-3中給出了Request類的定義,其簽名返回obejct實例的所有方法都會返回null。




此外,Request類還包括了在第1章中介紹過的parse()和getUri()方法。

2.2.3 Response類

ex02.pyrmont.Response類實現javax.servlet.servletResponse接口,類定義參見代碼清單2-4。該類提供了servletResponse接口中聲明的所有方法的實現。與Request類類似,除了getWriter()方法以外,大部分方法的實現都留空。


在getWriter()方法中,PrintWriter類的構造函數的第2個參數是一個布爾值,表示是否啟用autoFlush。對第2個參數傳入true表示對println()方法的任何調用都會刷新輸出。但是調用print()方法不會刷新輸出。
因此,如果在servlet的service()方法的最后一行調用print()方法,則該輸出內容不會被發(fā)送給瀏覽器。這個bug會在后續(xù)的版本中修改。
Response類中仍然保留了第1章中介紹過的sendStaticResource()方法。

2.2.4  StaticResourceProcessor類

ex02.pyrmont.StaticResourceProcessor類用于處理對靜態(tài)資源的請求。該類只有一個方法,即process()方法。代碼清單2-5給出了StaticResourceProcessor類的定義。

process()方法接收兩個參數:一個ex02.pyrmont.Request實例和一個ex02.pyrmont.Response實例。該方法僅僅調用Response對象的sendStaticResource()方法。

2.2.5 servletProcessor1類

ex02.pyrmont.servletProcessor1類的定義參見代碼清單2-6,該類用于處理對servlet資源的HTTP請求。
代碼清單2-6 servletProcessor1類的定義

package ex02.pyrmont; import java.net.URL; import java.net.URLClassLoader; import java.net.URLStreamHandler; import java.io.File; import java.io.IOException; import javax.servlet.Servlet; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; public class ServletProcessor1 { public void process(Request request, Response response) { String uri = request.getUri(); String servletName = uri.substring(uri.lastIndexOf("/") + 1); URLClassLoader loader = null; try { // create a URLClassLoader URL[] urls = new URL[1]; URLStreamHandler streamHandler = null; File classPath = new File(Constants.WEB_ROOT); // the forming of repository is taken from the // createClassLoader method in // org.apache.catalina.startup.ClassLoaderFactory String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ; // the code for forming the URL is taken from // the addRepository method in // org.apache.catalina.loader.StandardClassLoader. urls[0] = new URL(null, repository, streamHandler); loader = new URLClassLoader(urls); } catch (IOException e) { System.out.println(e.toString() ); } Class myClass = null; try { myClass = loader.loadClass(servletName); } catch (ClassNotFoundException e) { System.out.println(e.toString()); } Servlet servlet = null; try { servlet = (servlet) myClass.newInstance(); servlet.service((ServletRequest) request, (ServletResponse) response); } catch (Exception e) { System.out.println(e.toString()); } catch (Throwable e) { System.out.println(e.toString()); } } }

servletProcessor1類很簡單,只有一個方法:process()方法。該方法接收兩個參數,一個javax.servlet.ServletRequest實例和一個javax.servlet.ServletResponse實例。該方法通過調用getRequestUri()方法從ServletRequest對象中獲取URI:

String uri = request.getUri();

記住,URI的格式如下所示:

/servlet/servletName

其中,servletName是請求的servlet資源的類名。
為了載入servlet類,需要從URI中獲取servlet的類名。可以使用process()方法的下一行語句獲取servlet的類名:

String servletName = uri.substring(uri.lastIndexOf("/") + 1);

接下來,porcess()方法會載入該servlet類。為了載入類,需要創(chuàng)建一個類載入器,并且指明到哪里查找要載入的類。對于本節(jié)的servlet容器,類載入器會到Constant.WEB_ROOT指定的工作目錄下的webroot目錄中查找要載入的類。
注意 有關類載入器的詳細內容將在第8章中介紹。
為了載入一個servlet類,可以使用java.net.URLClassLoader類來完成,該類是java.lang.ClassLoader類的一個直接子類。一旦創(chuàng)建了URLClassLoader類的實例后,就可以使用它的loadClass()方法來載入servlet類。實例化URLClassLoader類很簡單。該類有三個構造函數,其中比較簡單的一個構造函數的簽名如下所示:

public URLClassLoader(URL[] urls);

其中,urls是一個java.net.URL對象數組,當載入一個類時每個URL對象都指明了類載入器要到哪里查找類。若一個URL以“/”結尾,則表明它指向的是一個目錄。否則,URL默認指向一個JAR文件,根據需要載入器會下載并打開這個JAR文件。
注意 在servlet容器中,類載入器查找servlet類的目錄稱為倉庫(repository)。
在應用程序中,類載入器只需要查找一個位置,即工作目錄下的webroot目錄。因此,需要先創(chuàng)建只有一個URL的一個數組。URL類提供了一系列構造函數,因此有很多種方法可以創(chuàng)建URL對象。對于本應用程序,使用與Tomcat中另一個類中使用的相同構造函數,該構造函數的簽名如下所示:

public URL(URL context, java.lang.String spec, URLStreamHandler hander) throws MalformedURLException

可以為第2個參數指定一個目錄,指定第1個和第3個參數為null,這樣就可以使用構造函數了。但是還有一個構造函數,它接受3個參數:
public URL(java.lang.String protocol, java.lang.String host, java.lang.String file) throws MalformedURLException
因此,若只使用如下語句,編譯器就無法知道要調用哪個構造函數了,并且會報錯:

new URL(null, aString, null);

因此,可以使用下面的代碼,對于編譯器指明第三個參數的類型:

URLStreamHandler streamHandler = null; new URL(null, aString, streamHandler);

第2個參數中的字符串指明了倉庫的路徑,也就是查找servlet類的目錄。可以使用下面的代碼生成倉庫:

String repository = (new URL("file", null, classPath.getCanonicalPath() + File.separator)).toString() ;

將上述代碼綜合到一起,就得到了創(chuàng)建URLCLassLoader實例的process()方法的部分代碼:

注意 生成倉庫后會調用org.apache.catalina.startup.ClassLoaderFactory類的createClassLoader()方法,生成URL對象后會調用org.apache.catalina.loader.StandardClassLoader類的addRepository()方法。這些方法將在后續(xù)章節(jié)中介紹。
有了類載入器后,就可以通過調用loadClass()方法來載入servlet類:

接下來,process()方法會創(chuàng)建已載入的servlet類的一個實例,將其向下轉型為javax.servlet.servlet,并調用其service()方法:

2.2.6 運行應用程序

要在Windows平臺上運行該程序,可以在工作目錄下執(zhí)行如下命令:

java -classpath ./lib/servlet.jar;./ ex02.pyrmont.HttpServer1

在Linux平臺上,需要用冒號分割兩個庫文件:

java -classpath ./lib/servlet.jar:./ ex02.pyrmont.HttpServer1

若想測試應用程序,可以在瀏覽器的地址欄或者URL框中輸入如下地址:

http://localhost:8080/index.html

http://localhost:8080/servlet/Primitiveservlet

當調用PrimitiveServlet類時,可以在瀏覽器中看到如下輸出:

Hello. Roses are red.

注意,你是看不到第2個字符串“Violets are blue”的,因為只有第1個字符串會發(fā)送到瀏覽器。這個問題將在第3章解決。

總結

以上是生活随笔為你收集整理的《深入剖析Tomcat》一2.2 应用程序 1的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。