即使世界明天毀滅,我也要在今天種下我的葡萄樹。
          posts - 112, comments - 14, trackbacks - 0, articles - 11

          Servlet容器工作原理

          Posted on 2006-05-24 17:08 閱讀(221) 評(píng)論(0)  編輯  收藏 所屬分類: WEB Design

          本文介紹servlet 容器的基本原理?,F(xiàn)有兩個(gè)Servlet容器,第一個(gè)很簡(jiǎn)單,第二個(gè)則是根據(jù)第一個(gè)寫出。為了使第一個(gè)容器盡量簡(jiǎn)單,所以沒有做得很完整。復(fù)雜一些的 servlet 容器 (包括 TOMCAT 4 和 5) 可以參考其他資料。

          兩個(gè)servlet容器都處理簡(jiǎn)單的servlet及staticResource。您可以使用 webroot/ 目錄下的 PrimitiveServlet 來測(cè)試它。復(fù)雜一些的 servlet會(huì)超出這些容器的容量,創(chuàng)建復(fù)雜servlet容器不是本文的內(nèi)容,所以在這里就不詳細(xì)介紹了。

            兩個(gè)應(yīng)用程序的類都封裝在ex02.pyrmont 包下。在理解應(yīng)用程序如何
          運(yùn)作 之前,您必須熟悉 javax.servlet.Servlet 接口。首先就來介紹這個(gè)接口。隨后,就介紹 servlet 容器服務(wù)servlet 的具體內(nèi)容。

            javax.servlet.Servlet 接口

            servlet編程,需要引用以下兩個(gè)類和接口:javax.servlet 和 javax.servlet.http,在這些類和接口中,javax.servlet.Servlet接口尤為重要。所有的 servlet 必須實(shí)現(xiàn)這個(gè)接口或繼承已實(shí)現(xiàn)這個(gè)接口的類。

            Servlet 接口有五個(gè)方法,如下:

           public void init(ServletConfig config) throws ServletException
           public void
          service (ServletRequest request, ServletResponse response) throws ServletException, java .io.IOException
           public void destroy()
           public ServletConfig getServletConfig()
           public java.lang.String getServletInfo()

            init、service和 destroy 方法是 Servlet 生命周期的方法。當(dāng) Servlet 類實(shí)例化后,容器加載 init,以通知 servlet 它已進(jìn)入服務(wù)行列。init 方法必須被加載,Servelt 才能接收和請(qǐng)求。如果要載入數(shù)據(jù)庫驅(qū)動(dòng)程序、初始化一些值等等,程序員可以重寫這個(gè)方法。在其他情況下,這個(gè)方法一般為空。

            service 方法由 Servlet 容器調(diào)用,以允許 Servlet 響應(yīng)一個(gè)請(qǐng)求。Servlet 容器傳遞 javax.servlet.ServletRequest 對(duì)象和 javax.servlet.ServletResponse 對(duì)象。ServletRequest 對(duì)象包含客戶端 HTTP 請(qǐng)求信息,ServletResponse 則封裝servlet 響應(yīng)。通過這兩個(gè)對(duì)象,您可以寫一些需要 servlet怎樣服務(wù)和客戶怎樣請(qǐng)求的代碼。

            從service中刪除Servlet實(shí)例之前,容器調(diào)用destroy方法。在servlet容器關(guān)閉或servlet 容器需要更多的內(nèi)存時(shí),就調(diào)用它。這個(gè)方法只有在servlet 的service 方法內(nèi)的所有線程都退出的時(shí)候,或在超時(shí)的時(shí)候才會(huì)被調(diào)用。在 servlet 容器調(diào)用 destroy方法之后,它將不再調(diào)用 servlet的 service方法。

            destroy 方法給了servlet機(jī)會(huì),來清除所有空閑資源(比如:內(nèi)存,文件處理和線程),以確保在內(nèi)存的持續(xù)狀態(tài)和 servlet的當(dāng)前狀態(tài)是同步的。Listing 2.1 包含了PrimitiveServlet 的代碼,此servlet非常簡(jiǎn)單,可以用它來測(cè)試本文的servlet容器應(yīng)用程序。

            PrimitiveServlet 類實(shí)現(xiàn)了javax.servlet.Servlet 并提供了五個(gè)servlet方法的接口。它做的事情也很簡(jiǎn)單:每次調(diào)用 init、service 或 destroy方法的時(shí)候,servlet就向控制口寫入方法名。service 方法也從ServletResponsec對(duì)象中獲得java.io.PrintWriter 對(duì)象,并發(fā)送字符串到瀏覽器。

            Listing 2.1.PrimitiveServlet.java

          import javax.servlet.*;
          import java.io.IOException;
          import java.io.PrintWriter;

          public class PrimitiveServlet implements Servlet {
          public void init(ServletConfig config) throws ServletException {
          System.out.println("init");
          }

          public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException {
          System.out.println("from service");
          PrintWriter out = response.getWriter();
          out.println("Hello.Roses are
          red .");
          out.print("Violets are blue.");
          }

          public void destroy() {
          System.out.println("destroy");
          }

          public String getServletInfo() {
          return null;
          }

          public ServletConfig getServletConfig() {
          return null;
          }
          }
          Application 1

            現(xiàn)在,我們從 servlet容器的角度來看看 servlet 編程。一個(gè)功能健全的 servlet容器對(duì)于每個(gè) servlet 的 HTTP請(qǐng)求會(huì)完成以下事情:

             1、當(dāng) servlet 第一次被調(diào)用的時(shí)候,加載了 servlet類并調(diào)用它的init方法(僅調(diào)用一次)

             2、響應(yīng)每次請(qǐng)求的時(shí)候 ,構(gòu)建一個(gè)javax.servlet.ServletRequest 和 javax.servlet.ServletResponse實(shí)例。
           
             3?、激活 servlet 的 service 方法,傳遞 ServletRequest 和 ServletResponse 對(duì)象。

             4、當(dāng)servlet 類關(guān)閉的時(shí)候,調(diào)用 servlet 的destroy 方法,并卸載 servlet 類。

            發(fā)生在 servlet 容器內(nèi)部的事就復(fù)雜多了。只是這個(gè)簡(jiǎn)單的 servlet 容器的功能不很健全,所以,這它只能運(yùn)行非常簡(jiǎn)單的servelt ,并不能調(diào)用 servlet 的 init 和destroy 方法。然而,它也執(zhí)行了以下動(dòng)作:

             1、等待 HTTP 請(qǐng)求。

             2、構(gòu)建 ServletRequest 和 ServletResponse 對(duì)象

             3、如果請(qǐng)求的是一個(gè)staticResource,就會(huì)激活StaticResourceProcessor實(shí)例的 process方法,傳遞ServletRequest 和 ServletResponse 對(duì)象。

             4、如果請(qǐng)求的是一個(gè)servlet ,載入該類,并激活它的service 方法,傳遞ServletRequest 和ServletResponse 對(duì)象。注意:在這個(gè)servlet 容器,每當(dāng) servlet被請(qǐng)求的時(shí)候該類就被載入。

            在第一個(gè)應(yīng)用程序中,servlet容器由六個(gè)類組成 。

             HttpServer1
             Request
             Response
             StaticResourceProcessor
             ServletProcessor1
             Constants

            這個(gè)程序的進(jìn)入口(靜態(tài) main 方法)是HttpServer 類。這個(gè)方法創(chuàng)建了HttpServer實(shí)例,并調(diào)用它的await方法等待 HTTP 請(qǐng)示,然后創(chuàng)建一個(gè) request 對(duì)象和 response對(duì)象,根據(jù)請(qǐng)求是否是staticResource還是 servlet 來分派它們到 StaticResourceProcessor實(shí)例或ServletProcessor實(shí)例。

            Constants 類包含 static find WEB_ROOT,它是從其他類引用的。 WEB_ROOT 指明 PrimitiveServlet 位置 和容器服務(wù)的staticResource。

            HttpServer1 實(shí)例等待 HTTP 請(qǐng)求,直到它收到一個(gè) shutdown 命令。發(fā)布 shutdown命令和前文是一樣的。

            HttpServer1 類

            此應(yīng)用程序內(nèi)的 HttpServer1類 與前文簡(jiǎn)單的 WEB 服務(wù)器應(yīng)用程序中的HttpServer 十分相似。但是,此應(yīng)用程序內(nèi)的 HttpServer1 能服務(wù)靜態(tài)資源和 servlet。如果要請(qǐng)求一個(gè)靜態(tài)資源,請(qǐng)輸入以下 URL:
          http://machineName:port/staticResource 。如果要請(qǐng)求一個(gè) servlet,請(qǐng)輸入以下 URL:

          http://machineName:port/servlet/servletClass

            如果您想在本地瀏覽器請(qǐng)求一個(gè) PrimitiveServle servlet ,請(qǐng)輸入以下 URL:

          http://localhost:8080/servlet/PrimitiveServlet

            下面Listing 2.2類的await方法,是等待一個(gè)HTTP請(qǐng)求,直到一個(gè)發(fā)布shutdown命令。與前文的await 方法相似。

            Listing 2.2. HttpServer1 類的 await 方法

          public void await() {
          ServerSocket serverSocket = null;
          int port = 8080;

          try {
          serverSocket = new ServerSocket(port, 1,
          InetAddress.getByName("127.0.0.1"));
          }
          catch (IOException e) {
          e.printStackTrace();
          System.exit(1);
          }

          // 循環(huán),等待一個(gè)請(qǐng)求
          while (!shutdown) {
          Socket socket = null;
          InputStream input = null;
          OutputStream output = null;

          try {
          socket = serverSocket.accept();
          input = socket.getInputStream();
          output = socket.getOutputStream();

          // 創(chuàng)建請(qǐng)求對(duì)象并解析
          Request request = new Request(input);
          request.parse();

          // 創(chuàng)建回應(yīng)對(duì)象
          Response response = new Response(output);
          response.setRequest(request);

          //檢測(cè)是否是 servlet 或靜態(tài)資源的請(qǐng)求
          //servlet 請(qǐng)求以 "/servlet/" 開始
          if (request.getUri().startsWith("/servlet/")) {
          ServletProcessor1 processor = new ServletProcessor1();
          processor.process(request, response);
          }
          else {
          StaticResourceProcessor processor =
          new StaticResourceProcessor();
          processor.process(request, response);
          }

          // 關(guān)閉socket
          socket.close();

          //檢測(cè)是否前面的 URI 是一個(gè) shutdown 命令
          shutdown = request.getUri().equals(SHUTDOWN_COMMAND);
          }
          catch (Exception e) {
          e.printStackTrace();
          System.exit(1);
          }
          }
          }

            此文 await 方法和前文的不同點(diǎn)就是,此文的 await 方法中的請(qǐng)求調(diào)度到StaticResourceProcessor 或 ervletProcessor 。

            如果 URI中包含 "/servlet/.",請(qǐng)求推進(jìn)到后面,否則,請(qǐng)求傳遞到 StaticResourceProcessor 實(shí)例。
          Request 類

            Servlet service 方法接受 servlet 容器的 javax.servlet.ServletRequest 和javax.servlet.ServletResponse 實(shí)例。因此,容器必須構(gòu)建 ServletRequest和ServletResponse對(duì)象,然后將其傳遞到正在被服務(wù)的service 方法。

            ex02.pyrmont.Request 類代表一個(gè)請(qǐng)求對(duì)象傳遞到 service 方法。同樣地,它必須實(shí)現(xiàn) javax.servlet.ServletRequest 接口。這個(gè)類必須提供接口內(nèi)所有方法的實(shí)現(xiàn)。這里盡量簡(jiǎn)化它并只實(shí)現(xiàn)幾個(gè)方法。要編譯 Request 類的話,必須提供這些方法的空實(shí)現(xiàn)。再來看看 request 類,內(nèi)部所有需要返回一個(gè)對(duì)象實(shí)例都返回null,如下:

          public Object getAttribute(String attribute) {
          return null;
          }

          public Enumeration getAttributeNames() {
          return null;
          }

          public String getRealPath(String path) {
          return null;
          }

            另外,request 類仍需有前文有介紹的 parse 和getUri 方法。

            Response 類

            response 類實(shí)現(xiàn) javax.servlet.ServletResponse,同樣,該類也必須提供接口內(nèi)所有方法的實(shí)現(xiàn)。類似于 Request 類,除 getWriter 方法外,其他方法的實(shí)現(xiàn)都為空。

          public PrintWriter getWriter() {
          // autoflush is true, println() will flush,
          // but print() will not.
          writer = new PrintWriter(output, true);
          return writer;

          }

            PrintWriter 類構(gòu)建器的第二個(gè)參數(shù)是一個(gè)代表是否啟用 autoflush 布爾值 ,如果為真,所有調(diào)用println 方法都 flush 輸出。而 print 調(diào)用則不 flush 輸出。因此,如果在servelt 的service 方法的最后一行調(diào)用 print方法,則從瀏覽器上看不到此輸出 。這個(gè)不完整性在后面的應(yīng)用程序內(nèi)會(huì)有調(diào)整。
          response 類也包含有前文中介紹的 sendStaticResource方法。

            StaticResourceProcessor 類

            StaticResourceProcessor 類用于服務(wù)靜態(tài)資源的請(qǐng)求。它唯一的方法是 process。

            Listing 2.3.StaticResourceProcessor 類的 process方法。

          public void process(Request request, Response response) {
          try {
          response.sendStaticResource();
          }
          catch (IOException e) {
          e.printStackTrace();
          }
          }

            process 方法接受兩個(gè)參數(shù):Request 和 Response 實(shí)例。它僅僅是調(diào)用 response 類的sendStaticResource 方法。
          主站蜘蛛池模板: 新巴尔虎右旗| 瑞昌市| 洛浦县| 淅川县| 青神县| 抚宁县| 罗定市| 太保市| 交口县| 平原县| 修武县| 绵阳市| 武威市| 塘沽区| 灵武市| 和政县| 莎车县| 墨竹工卡县| 当阳市| 南昌市| 清河县| 高碑店市| 阿合奇县| 丹棱县| 黄骅市| 恩施市| 乌鲁木齐县| 越西县| 巨鹿县| 罗山县| 民勤县| 古交市| 吴江市| 贵州省| 昌江| 观塘区| 台中县| 黑河市| 故城县| 牡丹江市| 衡阳县|