1.Servlet概述
a)Servlet,全城是Servlet Applet,服務器端小程序,是一個接口,定義了若干方法,要求所有的Servlet必須實現。
b)Servlet用於接收客戶端的請求,並對請求做出相應的相應。
c)Servlet中的方法:
>init:用於初始化Servlet;
>service:用於(執行)服務;
>destroy:在Servlet被銷毀前調用;
d)Servlet是一個接口,為了方便使用,官方提供了對應的實現類,關系如下:
Servlet: -- GenericServlet(c):通用協議的Servlet;
--HttpServlet(c):專門用於HTTP的Servlet;
2.定義Servlet並配置
2.1定義Servlet
測試時繼承了GenericServlet,實際使用時建議使用HttpServlet.
package com.bjsxt.servlet;
import java.io.IOException;
import javax.servlet.GenericServlet;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
public class FirstServlet extends GenericServlet{
public void service(ServletRequest req, ServletResponse res)throws ServletException, IOException{
System.out.println("FirstServlet.service()");
//響應信息
res.getWriter().print("<h1>Hello Servlet!</h1>");
}
}
2.2配置Servlet
在web.xml中配置Servlet,告訴Tomcat在客戶端訪問哪個路徑時,應該執行哪個Servlet.
<!-- 配置Servlet -->
<servlet>
<servlet-name>FirstServlet</servlet-name>
<servlet-class>com.bjsxt.servlet.FirstServlet</servlet-class>
</servlet>
<!-- 配置Servlet映射 -->
<servlet-mapping>
<servlet-name>FirstServlet</servlet-name>
<url-pattern>/abc</url-pattern>
<!-- http://localhost:8080/0529_servlet_hello/abc -->
</servlet-mapping>
3.Servlet的執行過程(圖略)
a)客戶端通過瀏覽器輸入URL地址訪問Tomcat
b)Tomcat解析URL路徑
c)到當前項目的web.xml中匹配Servlet的映射路徑;
---如果匹配成功,則調用對應的Servlet的service方法;
---如果沒有匹配成功,則繼續到Tomcat的web.xml中匹配。
d)在Tomcat的web.xml中,提供了兩個Servlet,分別為DefaultServlet和JspServlet.
---JspServlet用於處理jsp
---DefaultServlet處理沒有匹配到其他Servlet的所有請求,用於加載靜態資源或404異常。
4.Servlet配置詳解
a)web.xml的名稱不能改變,位置不能改變;
b)<servlet-name>和<servlet-class>要寫正確,必須要匹配;
c)關於<url-pattern>的幾種配置方式:
<servlet-mapping>
<servlet-name>FirstServlet</servlet-name>
<!-- 固定路徑, 必須以/開頭 -->
<url-pattern>/abc</url-pattern>
<!-- 以xxx結尾的路徑 -->
<url-pattern>*.sxt</url-pattern>
<!-- 訪問xxx下的路徑 -->
<url-pattern>/sxt/*</url-pattern>
<!-- 不可以使用如下的方式 -->
<!-- <url-pattern>/sxt/*.aaa</url-pattern> -->
<!-- 匹配所有的路徑, 包括jsp -->
<url-pattern>/*</url-pattern>
<!-- 匹配所有除了jsp之外的路徑 -->
<url-pattern>/</url-pattern>
</servlet-mapping>
5.解決405異常
a)在HttpServlet中,service方法用於分發請求,例如:如果是get方式,就調用doGet方法;如果是post方式,就調用doPost方法。
b)而HttpServlet中的doPost方法和doGet方法沒有做什么事,就發送了一個405異常,因此,一旦執行到這兩個方法就會報405異常。
c)解決405異常的兩種方式:
---子類重寫service方法:
public class DemoServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("DemoServlet.service()");
}
}
---子類重寫doGet和doPost方法:
public class DemoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("DemoServlet.doGet()");
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
System.out.println("DemoServlet.doPost()");
}
}
6.單例設計模式
a)設計模式是解決特定問題的最佳方案。
b)單例,單個對象,在對象的使用過程中,永遠都只創建一個對象;
c)餓漢式單例,類加載時就創建對象,由於靜態成員變量只被加載一次,所以保證了對象之創建一次;
package com.bjsxt.singleton;
/**
* 餓漢式單例
* 不管這個對象是否被使用, 先被創建
* @author Administrator
*
*/
public class HungrySingleton {
private static HungrySingleton instance = new HungrySingleton();
private HungrySingleton() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("創建對象[餓漢式]");
}
/**
* 靜態方法, 用於給其他類提供對象
*
* @return
*/
public static HungrySingleton getInstance() {
return instance;
}
}
d)懶漢式單例,在需要的時候才創建對象,多線程時不安全,需要使用雙重檢查機制保證線程安全;
package com.bjsxt.singleton;
/**
* 懶漢式單例
*
* @author Administrator
*
*/
public class LazySingleton {
private static LazySingleton instance;
private LazySingleton() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("創建對象[懶漢式]");
}
public static LazySingleton getInstance() {
if (instance == null) {
synchronized (LazySingleton.class) {
// Double Check, 雙重檢查
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
7.餓漢式單例和懶漢式單例的比較
a)餓漢式:
>代碼非常簡單。
>類加載時及創建對象,該對象可能並不會被使用。
>多線程下也可以保證單例的實現,沒有問題。
>省去了判斷,效率較高;
b)懶漢式:
>代碼較為復雜
>類加載時不會創建對象,需要時才創建,不會創建多余的對象。
>多線程時可能會有線程安全問題,需要進行Double Check。
>需要很多判斷,效率較低;
8.Servlet的生命周期
a)Servlet是單實例,多線程的
b)生命周期階段:
----創建:構造器,只創建一次;
----初始化:innit,只初始化一次;
---執行:service,累一次請求執行一次;
---銷毀:destroy,項目卸載或服務關閉時,Servlet被銷毀,銷毀前會由服務器調用destriy方法;
c)默認情況下,Servlet是懶漢式單例,對象是在第一次請求時被創建的。
d) 如果希望Servlet在服務器啟動時就創建, 可以在<servlet>標簽下通過<load-on-startup>標簽進行指定. 該標簽需要配置一個整數:
- 負整數: 和不配置一樣, 表示第一次請求時創建和初始化.
- 0和正整數: 表示服務器啟動時就創建和初始化, 數字越小, 被加載的優先級越高. 如果數字相同, 加載順序由服務器決定.