程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> javaweb Servlet開辟總結(一)

javaweb Servlet開辟總結(一)

編輯:關於JAVA

javaweb Servlet開辟總結(一)。本站提示廣大學習愛好者:(javaweb Servlet開辟總結(一))文章只能為提供參考,不一定能成為您想要的結果。以下是javaweb Servlet開辟總結(一)正文


1、Servlet簡介

  Servlet是sun公司供給的一門用於開辟靜態web資本的技巧。
  Sun公司在其API中供給了一個servlet接口,用戶若想用發一個靜態web資本(即開辟一個Java法式向閱讀器輸入數據),須要完成以下2個步調:
  1、編寫一個Java類,完成servlet接口。
  2、把開辟好的Java類安排到web辦事器中。
  依照一種商定俗成的稱謂習氣,平日我們也把完成了servlet接口的java法式,稱之為Servlet

2、Servlet的運轉進程

Servlet法式是由WEB辦事器挪用,web辦事器收到客戶真個Servlet拜訪要求後:
  ①Web辦事器起首檢討能否曾經裝載並創立了該Servlet的實例對象。假如是,則直接履行第④步,不然,履行第②步。
  ②裝載並創立該Servlet的一個實例對象。
  ③挪用Servlet實例對象的init()辦法。
  ④創立一個用於封裝HTTP要求新聞的HttpServletRequest對象和一個代表HTTP呼應新聞的HttpServletResponse對象,然後挪用Servlet的service()辦法並將要求和呼應對象作為參數傳遞出來。
  ⑤WEB運用法式被停滯或從新啟動之前,Servlet引擎將卸載Servlet,並在卸載之前挪用Servlet的destroy()辦法。

3、Servlet挪用圖

4、在Eclipse中開辟Servlet

  在eclipse中新建一個web project工程,eclipse會主動創立下圖所示目次構造:

4.1、Servlet接話柄現類

  Servlet接口SUN公司界說了兩個默許完成類,分離為:GenericServlet、HttpServlet。

  HttpServlet指可以或許處置HTTP要求的servlet,它在原有Servlet接口上添加了一些與HTTP協定處置辦法,它比Servlet接口的功效更加壯大。是以開辟人員在編寫Servlet時,平日應繼續這個類,而防止直接去完成Servlet接口。
  HttpServlet在完成Servlet接口時,覆寫了service辦法,該辦法體內的代碼會主動斷定用戶的要求方法,如為GET要求,則挪用HttpServlet的doGet辦法,如為Post要求,則挪用doPost辦法。是以,開辟人員在編寫Servlet時,平日只須要覆寫doGet或doPost辦法,而不要去覆寫service辦法。

4.2、經由過程Eclipse創立和編寫Servlet

  選中gacl.servlet.study包,右鍵→New→Servlet,以下圖所示:

  

  

  

如許,我們就經由過程Eclipse幫我們創立好一個名字為ServletDemo1的Servlet,創立好的ServletDemo01外面會有以下代碼:

package gacl.servlet.study;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ServletDemo1 extends HttpServlet {

  /**
   * The doGet method of the servlet. <br>
   *
   * This method is called when a form has its tag value method equals to get.
   * 
   * @param request the request send by the client to the server
   * @param response the response send by the server to the client
   * @throws ServletException if an error occurred
   * @throws IOException if an error occurred
   */
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
    out.println("<HTML>");
    out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
    out.println(" <BODY>");
    out.print("  This is ");
    out.print(this.getClass());
    out.println(", using the GET method");
    out.println(" </BODY>");
    out.println("</HTML>");
    out.flush();
    out.close();
  }

  /**
   * The doPost method of the servlet. <br>
   *
   * This method is called when a form has its tag value method equals to post.
   * 
   * @param request the request send by the client to the server
   * @param response the response send by the server to the client
   * @throws ServletException if an error occurred
   * @throws IOException if an error occurred
   */
  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {

    response.setContentType("text/html");
    PrintWriter out = response.getWriter();
    out.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">");
    out.println("<HTML>");
    out.println(" <HEAD><TITLE>A Servlet</TITLE></HEAD>");
    out.println(" <BODY>");
    out.print("  This is ");
    out.print(this.getClass());
    out.println(", using the POST method");
    out.println(" </BODY>");
    out.println("</HTML>");
    out.flush();
    out.close();
  }

}

  這些代碼都是Eclipse主動生成的,而web.xml文件中也多了<servlet></servlet>和<servlet-mapping></servlet-mapping>兩對標簽,這兩對標簽是設置裝備擺設ServletDemo1的,以下圖所示:

然後我們便可以經由過程閱讀器拜訪ServletDemo1這個Servlet,以下圖所示:

5、Servlet開辟留意細節

5.1、Servlet拜訪URL映照設置裝備擺設

  因為客戶端是經由過程URL地址拜訪web辦事器中的資本,所以Servlet法式若想被外界拜訪,必需把servlet法式映照到一個URL地址上,這個任務在web.xml文件中應用<servlet>元素和<servlet-mapping>元素完成。
  <servlet>元素用於注冊Servlet,它包括有兩個重要的子元素:<servlet-name>和<servlet-class>,分離用於設置Servlet的注冊稱號和Servlet的完全類名。
一個<servlet-mapping>元素用於映照一個已注冊的Servlet的一個對外拜訪途徑,它包括有兩個子元素:<servlet-name>和<url-pattern>,分離用於指定Servlet的注冊稱號和Servlet的對外拜訪途徑。例如:

<servlet>
  <servlet-name>ServletDemo1</servlet-name>
  <servlet-class>gacl.servlet.study.ServletDemo1</servlet-class>
 </servlet>

 <servlet-mapping>
  <servlet-name>ServletDemo1</servlet-name>
  <url-pattern>/servlet/ServletDemo1</url-pattern>
 </servlet-mapping>
  統一個Servlet可以被映照到多個URL上,即多個<servlet-mapping>元素的<servlet-name>子元素的設置值可所以統一個Servlet的注冊名。 例如:
<servlet>
  <servlet-name>ServletDemo1</servlet-name>
  <servlet-class>gacl.servlet.study.ServletDemo1</servlet-class>
 </servlet>

 <servlet-mapping>
  <servlet-name>ServletDemo1</servlet-name>
  <url-pattern>/servlet/ServletDemo1</url-pattern>
 </servlet-mapping>
 <servlet-mapping>
  <servlet-name>ServletDemo1</servlet-name>
  <url-pattern>/1.htm</url-pattern>
 </servlet-mapping>
  <servlet-mapping>
  <servlet-name>ServletDemo1</servlet-name>
  <url-pattern>/2.jsp</url-pattern>
 </servlet-mapping>
  <servlet-mapping>
  <servlet-name>ServletDemo1</servlet-name>
  <url-pattern>/3.php</url-pattern>
 </servlet-mapping>
  <servlet-mapping>
  <servlet-name>ServletDemo1</servlet-name>
  <url-pattern>/4.ASPX</url-pattern>
 </servlet-mapping>

  經由過程下面的設置裝備擺設,當我們想拜訪稱號是ServletDemo1的Servlet,可使用以下的幾個地址去拜訪:

  http://localhost:8080/JavaWeb_Servlet_Study_20140531/servlet/ServletDemo1

  http://localhost:8080/JavaWeb_Servlet_Study_20140531/1.htm

  http://localhost:8080/JavaWeb_Servlet_Study_20140531/2.jsp

  http://localhost:8080/JavaWeb_Servlet_Study_20140531/3.php

  http://localhost:8080/JavaWeb_Servlet_Study_20140531/4.ASPX

  ServletDemo1被映照到了多個URL上。

5.2、Servlet拜訪URL應用*通配符映照  

在Servlet映照到的URL中也能夠應用*通配符,然則只能有兩種固定的格局:一種格局是"*.擴大名",另外一種格局是以正斜槓(/)開首並以"/*"開頭。例如:

<servlet>
  <servlet-name>ServletDemo1</servlet-name>
  <servlet-class>gacl.servlet.study.ServletDemo1</servlet-class>
 </servlet>

  <servlet-mapping>
  <servlet-name>ServletDemo1</servlet-name>
  <url-pattern>/*</url-pattern>

  *可以婚配隨意率性的字符,所以此時可以用隨意率性的URL去拜訪ServletDemo1這個Servlet,以下圖所示:

關於以下的一些映照關系:
  Servlet1 映照到 /abc/*
  Servlet2 映照到 /*
  Servlet3 映照到 /abc
  Servlet4 映照到 *.do
成績:
  當要求URL為“/abc/a.html”,“/abc/*”和“/*”都婚配,哪一個servlet呼應
      Servlet引擎將挪用Servlet1。
  當要求URL為“/abc”時,“/abc/*”和“/abc”都婚配,哪一個servlet呼應
      Servlet引擎將挪用Servlet3。
  當要求URL為“/abc/a.do”時,“/abc/*”和“*.do”都婚配,哪一個servlet呼應
      Servlet引擎將挪用Servlet1。
  當要求URL為“/a.do”時,“/*”和“*.do”都婚配,哪一個servlet呼應
      Servlet引擎將挪用Servlet2。
  當要求URL為“/xxx/yyy/a.do”時,“/*”和“*.do”都婚配,哪一個servlet呼應
      Servlet引擎將挪用Servlet2。
  婚配的准繩就是"誰長得更像就找誰"

5.3、Servlet與通俗Java類的差別  

  Servlet是一個供其他Java法式(Servlet引擎)挪用的Java類,它不克不及自力運轉,它的運轉完整由Servlet引擎來掌握和調劑。
  針對客戶真個屢次Servlet要求,平日情形下,辦事器只會創立一個Servlet實例對象,也就是說Servlet實例對象一旦創立,它就會駐留在內存中,為後續的其它要求辦事,直至web容器加入,servlet實例對象才會燒毀。
  在Servlet的全部性命周期內,Servlet的init辦法只被挪用一次。而對一個Servlet的每次拜訪要求都招致Servlet引擎挪用一次servlet的service辦法。關於每次拜訪要求,Servlet引擎都邑創立一個新的HttpServletRequest要求對象和一個新的HttpServletResponse呼應對象,然後將這兩個對象作為參數傳遞給它挪用的Servlet的service()辦法,service辦法再依據要求方法分離挪用doXXX辦法。

  假如在<servlet>元素中設置裝備擺設了一個<load-on-startup>元素,那末WEB運用法式在啟動時,就會裝載並創立Servlet的實例對象、和挪用Servlet實例對象的init()辦法。
    舉例:

<servlet>
    <servlet-name>invoker</servlet-name>
    <servlet-class>
      org.apache.catalina.servlets.InvokerServlet
    </servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

  用處:為web運用寫一個InitServlet,這個servlet設置裝備擺設為啟動古裝載,為全部web運用創立需要的數據庫表和數據。

5.4、缺省Servlet

  假如某個Servlet的映照途徑僅僅為一個正斜槓(/),那末這個Servlet就成為以後Web運用法式的缺省Servlet。
  但凡在web.xml文件中找不到婚配的<servlet-mapping>元素的URL,它們的拜訪要求都將交給缺省Servlet處置,也就是說,缺省Servlet用於處置一切其他Servlet都不處置的拜訪要求。 例如:

<servlet>
  <servlet-name>ServletDemo2</servlet-name>
  <servlet-class>gacl.servlet.study.ServletDemo2</servlet-class>
  <load-on-startup>1</load-on-startup>
 </servlet>
 
 <!-- 將ServletDemo2設置裝備擺設成缺省Servlet -->
 <servlet-mapping>
  <servlet-name>ServletDemo2</servlet-name>
  <url-pattern>/</url-pattern>
 </servlet-mapping>

  當拜訪不存在的Servlet時,就應用設置裝備擺設的默許Servlet停止處置,以下圖所示:

  在<tomcat的裝置目次>\conf\web.xml文件中,注冊了一個稱號為org.apache.catalina.servlets.DefaultServlet的Servlet,並將這個Servlet設置為了缺省Servlet。

<servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
      <param-name>debug</param-name>
      <param-value>0</param-value>
    </init-param>
    <init-param>
      <param-name>listings</param-name>
      <param-value>false</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>

 <!-- The mapping for the default servlet -->
  <servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  當拜訪Tomcat辦事器中的某個靜態HTML文件和圖片時,現實上是在拜訪這個缺省Servlet。

5.5、Servlet的線程平安成績

  當多個客戶端並發拜訪統一個Servlet時,web辦事器會為每個客戶真個拜訪要求創立一個線程,並在這個線程上挪用Servlet的service辦法,是以service辦法內假如拜訪了統一個資本的話,就有能夠激發線程平安成績。例以下面的代碼:

不存在線程平安成績的代碼:

package gacl.servlet.study;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ServletDemo3 extends HttpServlet {

  
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    
    /**
     * 當多線程並發拜訪這個辦法外面的代碼時,會存在線程平安成績嗎
     * i變量被多個線程並發拜訪,然則沒有線程平安成績,由於i是doGet辦法外面的部分變量,
     * 當有多個線程並發拜訪doGet辦法時,每個線程外面都有本身的i變量,
     * 各個線程操作的都是本身的i變量,所以不存在線程平安成績
     * 多線程並發拜訪某一個辦法的時刻,假如在辦法外部界說了一些資本(變量,聚集等)
     * 那末每個線程都有這些器械,所以就不存在線程平安成績了
     */
    int i=1;
    i++;
    response.getWriter().write(i);
  }

  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    doGet(request, response);
  }

}

存在線程平安成績的代碼:

package gacl.servlet.study;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class ServletDemo3 extends HttpServlet {

  int i=1;
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    
    i++;
    try {
      Thread.sleep(1000*4);
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
    response.getWriter().write(i+"");
  }

  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    doGet(request, response);
  }

}

  把i界說玉成局變量,當多個線程並發拜訪變量i時,就會存在線程平安成績了,以下圖所示:同時開啟兩個閱讀器模仿並發拜訪統一個Servlet,原來正常來講,第一個閱讀器應當看到2,而第二個閱讀器應當看到3的,成果兩個閱讀器都看到了3,這就不正常。

  線程平安成績只存在多個線程並發操作統一個資本的情形下,所以在編寫Servlet的時刻,假如並發拜訪某一個資本(變量,聚集等),就會存在線程平安成績,那末該若何處理這個成績呢?

先看看上面的代碼:

package gacl.servlet.study;

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


public class ServletDemo3 extends HttpServlet {

  int i=1;
  public void doGet(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    /**
     * 加了synchronized後,並發拜訪i時就不存在線程平安成績了,
     * 為何加了synchronized後就沒有線程平安成績了呢?
     * 假設如今有一個線程拜訪Servlet對象,那末它就先拿到了Servlet對象的那把鎖
     * 比及它履行完以後才會把鎖還給Servlet對象,因為是它先拿到了Servlet對象的那把鎖,
     * 所以當有其余線程來拜訪這個Servlet對象時,因為鎖曾經被之前的線程拿走了,前面的線程只能列隊等待了
     * 
     */
    synchronized (this) {//在java中,每個對象都有一把鎖,這裡的this指的就是Servlet對象
      i++;
      try {
        Thread.sleep(1000*4);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      response.getWriter().write(i+"");
    }
    
  }

  public void doPost(HttpServletRequest request, HttpServletResponse response)
      throws ServletException, IOException {
    doGet(request, response);
  }

}

  如今這類做法是給Servlet對象加了一把鎖,包管任什麼時候候都只要一個線程在拜訪該Servlet對象外面的資本,如許就不存在線程平安成績了,以下圖所示:

  這類做法固然處理了線程平安成績,然則編寫Servlet卻切切不克不及用這類方法處置線程平安成績,假設有9999小我同時拜訪這個Servlet,那末這9999小我必需按前後次序列隊輪番拜訪。

  針對Servlet的線程平安成績,Sun公司是供給有處理計劃的:讓Servlet去完成一個SingleThreadModel接口,假如某個Servlet完成了SingleThreadModel接口,那末Servlet引擎將以單線程形式來挪用其service辦法。
  檢查Sevlet的API可以看到,SingleThreadModel接口中沒有界說任何辦法和常量,在Java中,把沒有界說任何辦法和常量的接口稱之為標志接口,常常看到的一個最典范的標志接口就是"Serializable",這個接口也是沒有界說任何辦法和常量的,標志接口在Java中有甚麼用呢?重要感化就是給某個對象打上一個標記,告知JVM,這個對象可以做甚麼,好比完成了"Serializable"接口的類的對象便可以被序列化,還有一個"Cloneable"接口,這個也是一個標志接口,在默許情形下,Java中的對象是不許可被克隆的,就像實際生涯中的人一樣,不許可克隆,然則只需完成了"Cloneable"接口,那末對象便可以被克隆了。

  讓Servlet完成了SingleThreadModel接口,只需在Servlet類的界說中增長完成SingleThreadModel接口的聲明便可。 
  關於完成了SingleThreadModel接口的Servlet,Servlet引擎依然支撐對該Servlet的多線程並發拜訪,其采取的方法是發生多個Servlet實例對象,並發的每一個線程分離挪用一個自力的Servlet實例對象。
  完成SingleThreadModel接口其實不能真正處理Servlet的線程平安成績,由於Servlet引擎會創立多個Servlet實例對象,而真正意義上處理多線程平安成績是指一個Servlet實例對象被多個線程同時挪用的成績。現實上,在Servlet API 2.4中,曾經將SingleThreadModel標志為Deprecated(過時的)。
以上就是本文的全體內容,願望對年夜家的進修有所贊助。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved