Servlet使用的一些細節問題

Servlet一些細節:

1.     由於客戶端是通過URL地址訪問web服務器中的資源,所以Servlet程序若想被外界訪問的話,必須把servlet程序映射到一個URL地址上,這個工作在web.xml文件中使用<servlet>元素和<servlet-mapping>元素完成。

2.     <servlet>元素用於註冊Servlet,它包含有兩個主要的子元素:<servlet-name><servlet-class>,分別用於設置Servlet的註冊名稱和Servlet的完整類名。

3.     一個<servlet-mapping>元素用於映射一個已經註冊的Servlet的一個對外的訪問路徑,它包含兩個子元素:<servlet-name><url-pattern>,分別用於指定Servlet的註冊名稱和Servlet的對外訪問路徑。

注意:對於一個已經註冊的Servlet可以被多次映射。

4.     在對servlet進行映射的時候,可以使用通配符

有兩種格式:

第一種格式:*.擴展名 比如說*.do  *.ss

第二種格式:以/開頭並且以/*結尾 比如/*   /news/*

 

在通配符進行匹配的時候,要參考的標準

(1)     看誰的匹配度高,誰就被選中

(2)     *.do的優先級最低

5.     Servlet單例問題

Servlet被第一次訪問後,就被加載到內存,以後該實例對各個請求服務即在使用中是單例的。服務器只會創建一個Servlet實例對象,也就是說該Servlet實例對象一旦創建就會駐留在內存中,爲後續的其他請求服務,直到web容器退出或者reloadweb應用程序,servlet對象纔會被銷燬。

因爲Servlet是單例,因此會出現線程安全問題,比如:

售票系統,如果不加同步機制,則會出現問題。

 

給大家的一個原則:

(1)     如果一個變量需要多個用戶共享,則應當在訪問該變量的時候,加同步機制synchronize(對象){

//同步代碼

}

public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException {
		response.setContentType("text/html");
		PrintWriter out = response.getWriter();
		int j = 0;
		j++;
		out.println("hello "+new java.util.Date().toString()+" j="+j);
		synchronized (this) {
			if(ticket > 0) {
				System.out.println("你買到票了");
				//休眠
				try {
					Thread.sleep(10 * 1000);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				ticket--;
				
			}else {
				System.out.println("你沒有買到票");
			}
		}
		
		
	}


(2)     如果一個變量不需要共享,則直接在doGet()或者doPost()中定義即可。這樣不會存在線程安全問題。

6.     servlet中的<load-on-startup>配置

需求:當我們的網站啓動的時候,可能會要求初始化一些數據,(比如創建臨時表),再比如:

我們的網站要有一些定時完成的任務【定時寫日誌,定時備份數據庫定時發送郵件】

解決方法:可以通過<load-on-startup>配合線程相關知識搞定。

先說明<load-on-startup>:通過配置它,我麼可以指定某個Servlet自動創建。

 

  <servlet>
    <description>This is the description of my J2EE component</description>
    <display-name>This is the display name of my J2EE component</display-name>
    <servlet-name>MyInitServlet1</servlet-name>
    <servlet-class>com.sgr.servlet.MyInitServlet1</servlet-class>
    <!--1表示該Servlet被init的順序-->
    <load-on-startup>2</load-on-startup>
  </servlet>
  <servlet>
    <description>This is the description of my J2EE component</description>
    <display-name>This is the display name of my J2EE component</display-name>
    <servlet-name>MyInitServlet2</servlet-name>
    <servlet-class>com.sgr.servlet.MyInitServlet2</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>

配置好<load-on-startup>之後就可以在init函數當中進行相關代碼的編寫了,例如我在另外一個包當中寫了一個簡單的模擬發郵件java程序,代碼如下:

package com.sgr.model;

public class SendEmailThread extends Thread{

	public void run() {
		// TODO Auto-generated method stub
		int i = 0;
		try {
			//每休眠一分鐘,就去掃描sendmail,看看哪封信應當被髮出
			while(true) {
			Thread.sleep(10*1000);
			System.out.println("發出第"+(++i)+"郵件");//javamail技術
			}
			
		} catch (Exception e) {
			// TODO: handle exception
			e.printStackTrace();
		}
	}
	
}

之後我在我之前寫好的Servlet的init函數當中寫一些需要初始化而做的工作。代碼如下:

public void init() throws ServletException {
		// Put your code here
		System.out.println("MyInitServlet1的Init被調用");
		//完成初始化任務
		System.out.println("創建數據庫,表,讀取");
		//創建一個線程
		SendEmailThread sendEmailThread = new SendEmailThread();
		sendEmailThread.start();
	}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章