http://blog.csdn.net/sunxianghuang/article/details/52107376
# Servlet
## Servlet接口
**[java]**?[view plain](http://blog.csdn.net/sunxianghuang/article/details/52107376# "view plain")?[copy](http://blog.csdn.net/sunxianghuang/article/details/52107376# "copy")
1. public?interface?Servlet?{??
2. ??
3. ????public?void?init(ServletConfig?config)?throws?ServletException;??
4. ??
5. ????public?ServletConfig?getServletConfig();??
6. ??
7. ????public?void?service(ServletRequest?req,?ServletResponse?res)??
8. ????throws?ServletException,?IOException;??
9. ??
10. ????public?String?getServletInfo();??
11. ??
12. ????public?void?destroy();??
13. }??
### Init()
在Servlet實例化之后,Servlet容器會調用init()方法,來初始化該對象,主要是為了讓Servlet對象在處理客戶端請求前可以完成一些初始化的工作,例如:建立數據庫連接、獲取配置信息等。對于每一個Servlet實例,init()方法只能被調用一次。init()方法有一個類型為ServletConfig的參數,Servlet容器通過這個參數向Servlet傳遞配置信息。Servlet使用Servlet對象從Web應用程序的配置信息中獲取以***名-值對***形式提供的***初始化參數***。另外,在Servlet中,還可以通過ServletConfig對行啊獲取描述Servlet運行環境的ServletContext對象,使用該對象,Servlet可以和它的Servlet容器進行通信。
### service()
容器調用service()方法來處理客戶端請求。要注意,在Servlet方法被容器調用之前,必須確保init()方法正確完成。容器會構造一個表示客戶端請求信息的請求對象(類型為ServletRequest)和一個用于對客戶端進行響應的響應對象(類型為ServletResponse)作為參數傳遞給service()方法。在service方法中,Servlet對象通過ServletRequest對象得到客戶端的相關信息和請求信息,在對請求進行處理后,調用ServletResponse對象的方法設置響應信息。
### destory()
當容器檢測到一個Servlet對象應該從服務中被移除的時候,容器會調用該對象的destory()方法,以便讓Servlet對象可以釋放它所使用的資源,同時保存數據到持久存儲設備中,例如將內存中的數據保存到數據庫中,關閉數據庫連接等。當需要釋放內存或者容器關閉時,容器就會調用Servlet對象的destory()方法。在Servlet容器調用destory()方法之前,如果還有其他線程正在service()方法中執行,容器將會等待這些線程執行完畢或等待服務器設定的超時時間到達。一旦Servlet對象的destory()方法被調用,容器不會再把其他的請求發送給該對象。如果需要該Servlet再次為客戶端服務,容器將會重新產生一個Servlet對象來處理客戶端請求。在destory()方法調用之后,容器會釋放這個Servlet對象,在隨后的時間內,該對象會被Java垃圾收集器所回收。
### getServletConfig()
該方法返回容器調用init()方法時傳遞給Servlet對象的ServletConfig對象,ServletConfig對象包含了Servlet的初始化參數。
### getServletInfo()
返回一個String類型的字符串,其中包括了關于Servlet的信息,例如,作者、版本和版權。
## ServletConfig接口
**[java]**?[view plain](http://blog.csdn.net/sunxianghuang/article/details/52107376# "view plain")?[copy](http://blog.csdn.net/sunxianghuang/article/details/52107376# "copy")
1. public?interface?ServletConfig?{??
2. ??
3. ????public?String?getServletName();//返回Servlet實例的名字??
4. ??
5. ????public?ServletContext?getServletContext();//返回Servlet上下文對象??
6. ??????
7. ????public?String?getInitParameter(String?name);//返回名稱為name的初始化參數的值??
8. ??
9. ????public?Enumeration?getInitParameterNames();//返回Servlet所有初始化參數的名字和枚舉集合??
10. }??
## GenericServlet抽象類
**[java]**?[view plain](http://blog.csdn.net/sunxianghuang/article/details/52107376# "view plain")?[copy](http://blog.csdn.net/sunxianghuang/article/details/52107376# "copy")
1. public?abstract?class?GenericServlet???
2. ????implements?Servlet,?ServletConfig,?java.io.Serializable??
3. {//GenericServlet抽象類定義了一個通用的、不依賴于具體協議的Servlet,簡化子類的實現。??
4. ??
5. ????private?transient?ServletConfig?config;//config為transient,不參與序列化??
6. ??
7. ????public?GenericServlet()?{?}??
8. ??????
9. ????public?void?destroy()?{??
10. ????}??
11. ??????
12. ????public?String?getInitParameter(String?name)?{??
13. ????return?getServletConfig().getInitParameter(name);??
14. ????}??
15. ??????
16. ????public?Enumeration?getInitParameterNames()?{??
17. ????return?getServletConfig().getInitParameterNames();??
18. ????}?????
19. ??????
20. ????public?ServletConfig?getServletConfig()?{??
21. ????return?config;??
22. ????}??
23. ??????
24. ????public?ServletContext?getServletContext()?{??
25. ????return?getServletConfig().getServletContext();??
26. ????}??
27. ??
28. ????public?String?getServletInfo()?{??
29. ????return?"";??
30. ????}??
31. ????//對Servlet接口中init()方法的實現。其中調用了不帶參數的的init()方法。??
32. ????public?void?init(ServletConfig?config)?throws?ServletException?{??
33. ????this.config?=?config;??
34. ????this.init();??
35. ????}??
36. ????//不帶參數的init()方法。通常我們在編寫繼承自GenericServlet的Servlet類時,只需重寫該方法。??
37. ??
38. ????public?void?init()?throws?ServletException?{??
39. ??
40. ????}??
41. ????public?void?log(String?msg)?{??
42. ????getServletContext().log(getServletName()?+?":?"+?msg);??
43. ????}??
44. ????public?void?log(String?message,?Throwable?t)?{??
45. ????getServletContext().log(getServletName()?+?":?"?+?message,?t);??
46. ????}??
47. ??????
48. ????public?abstract?void?service(ServletRequest?req,?ServletResponse?res)??
49. ????throws?ServletException,?IOException;??
50. ??
51. ??
52. ????public?String?getServletName()?{??
53. ????????return?config.getServletName();??
54. ????}??
55. }??
## HTTPServlet抽象類
**[java]**?[view plain](http://blog.csdn.net/sunxianghuang/article/details/52107376# "view plain")?[copy](http://blog.csdn.net/sunxianghuang/article/details/52107376# "copy")
1. public?abstract?class?HttpServlet?extends?GenericServlet??
2. ????implements?java.io.Serializable??
3. {??
4. //絕大多數的網絡應用中,都是客戶端(瀏覽器)通過HTTP協議去訪問服務器端的資源。??
5. //而我們所編寫的Servle也主要是應用于HTTP協議的請求和響應。該抽象類簡化了開發應用于HTTP協議的Servlet。??
6. ......??
7. ????????//對GenericServlet類中service()方法的實現。??
8. ????public?void?service(ServletRequest?req,?ServletResponse?res)?throws?ServletException,?IOException?{??
9. ????????HttpServletRequest?request;??
10. ????????HttpServletResponse?response;??
11. ????????????????//首先進行顯示類型轉換??
12. ????????try?{??
13. ????????????request?=?(HttpServletRequest)?req;??
14. ????????????response?=?(HttpServletResponse)?res;??
15. ????????}?catch?(ClassCastException?e)?{??
16. ????????????throw?new?ServletException("non-HTTP?request?or?response");??
17. ????????}??
18. ????????service(request,?response);//調用下一個service方法??
19. ????}??
20. ????????//在編寫HTTPServlet子類時,通常不需要覆蓋該方法,而只需要重寫相應的doXXX()方法。??
21. ????protected?void?service(HttpServletRequest?req,?HttpServletResponse?resp)?throws?ServletException,?IOException?{??
22. ????????String?method?=?req.getMethod();//獲取HTTP請求方法的類型??
23. ????????????????//HTTP1.1中定義了7種請求方法:Get、Post、Head、Put、Delete、Trace和Options??
24. ????????????????//然后根據請求方法的類型,調用相應的doXXX()方法??
25. ??
26. ????????if?(method.equals(METHOD_GET))?{??
27. ????????????long?lastModified?=?getLastModified(req);??
28. ????????????if?(lastModified?==?-1)?{??
29. ????????????????//?servlet?doesn't?support?if-modified-since,?no?reason??
30. ????????????????//?to?go?through?further?expensive?logic??
31. ????????????????doGet(req,?resp);??
32. ????????????}?else?{??
33. ????????????????long?ifModifiedSince?=?req.getDateHeader(HEADER_IFMODSINCE);??
34. ????????????????if?(ifModifiedSince?1000?*?1000))?{??
35. ????????????????????//?If?the?servlet?mod?time?is?later,?call?doGet()??
36. ????????????????????//?Round?down?to?the?nearest?second?for?a?proper?compare??
37. ????????????????????//?A?ifModifiedSince?of?-1?will?always?be?less??
38. ????????????????????maybeSetLastModified(resp,?lastModified);??
39. ????????????????????doGet(req,?resp);??
40. ????????????????}?else?{??
41. ????????????????????resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);??
42. ????????????????}??
43. ????????????}??
44. ??
45. ????????}?else?if?(method.equals(METHOD_HEAD))?{??
46. ????????????long?lastModified?=?getLastModified(req);??
47. ????????????maybeSetLastModified(resp,?lastModified);??
48. ????????????doHead(req,?resp);??
49. ??
50. ????????}?else?if?(method.equals(METHOD_POST))?{??
51. ????????????doPost(req,?resp);??
52. ??
53. ????????}?else?if?(method.equals(METHOD_PUT))?{??
54. ????????????doPut(req,?resp);??
55. ??
56. ????????}?else?if?(method.equals(METHOD_DELETE))?{??
57. ????????????doDelete(req,?resp);??
58. ??
59. ????????}?else?if?(method.equals(METHOD_OPTIONS))?{??
60. ????????????doOptions(req,?resp);??
61. ??
62. ????????}?else?if?(method.equals(METHOD_TRACE))?{??
63. ????????????doTrace(req,?resp);??
64. ??
65. ????????}?else?{??
66. ????????????//不支持的請求方法,提示錯誤??
67. ????????????//?Note?that?this?means?NO?servlet?supports?whatever??
68. ????????????//?method?was?requested,?anywhere?on?this?server.??
69. ????????????String?errMsg?=?lStrings.getString("http.method_not_implemented");??
70. ????????????Object[]?errArgs?=?new?Object[1];??
71. ????????????errArgs[0]?=?method;??
72. ????????????errMsg?=?MessageFormat.format(errMsg,?errArgs);??
73. ??
74. ????????????resp.sendError(HttpServletResponse.SC_NOT_IMPLEMENTED,?errMsg);??
75. ????????}??
76. ????}??
77. ??
78. ......}??
## Servlet生命周期
Servlet運行在Servlet容器中,其生命周期由容器來管理。Servlet的生命周期通過Servlet接口中的init()、service()和destory()方法來表示。

注:如果需要讓Servlet容器在啟動時自動加載Servlet,可以在web.xml文件中配置。
## 單實例多線程的Servlet模型

Servlet規范中定義,默認情況下(Servlet不是在分布式的環境中部署),Servlet容器對聲明的每一個Servlet,只創建一個實例。如果有多個客戶端請求同時訪問這個Servlet,Servlet容器如何處理多個請求呢?答案是采用多線程,Servlet容器維護一個線程池來服務請求。當容器接收到一個訪問Servlet的請求,調度者線程從線程池中選取一個工作線程,將請求傳遞給該線程,然后由這個線程執行Servlet的service()方法。
### 線程安全的Servlet
***變量的線程安全***
因為Servlet是單實例多線程模型,多個線程共享一個Servlet實例,因此對于實例變量的訪問是非線程安全的。
建議:在Servlet中盡可能的使用局部變量,應該只使用只讀的實例變量和靜態變量。如果非得使用共享的實例變量或靜態變量,在修改共享變量時應該注意線程同步。
***屬性的線程安全***
在Servlet中,可以訪問保存在ServletContext、HttpSession和ServletRequest對象中的屬性。那么這三種不同范圍的對象,屬性訪問是否是線程安全的呢?
***ServletContext***:該對象被Web應用程序的所有Servlet共享,多線程環境下肯定是非線程安全的。
***HttpSession***:HttpSession對象只能在同屬于一個Session的請求線程中共享。對于同一個Session,我們可能會認為在同一時刻只有一個用戶請求,因此,Session對象的屬性訪問是線程安全的。***但是***,如果用戶打開多個同屬于一個進程的瀏覽器窗口,在這些窗口中的訪問請求同屬于一個Session,對于多個線程的并發修改顯然不是線程安全的。
***ServletRequest***:因為Servlet容器對它所接收到的每一個請求,都創建一個新的ServletRequest對象,所以ServletRequest對象只在一個線程中被訪問,因此對ServletRequest的屬性訪問是線程安全的。但是,如果在Servlet中創建了自己的線程,那么對ServletRequest的屬性訪問的線程安全性就得自己去保證。此外,如果作死的將當前請求的Servlet通過HttpSession或者ServletContext共享,那當然也是非線程安全的。
## 相關問題
***1、重定向和轉發的區別***


# JSP
JSP是一種建立在Servlet規范提供的功能之上的動態網頁技術,它通過在網頁文件中嵌入腳本代碼,用于產生動態內容。
JSP文件在用戶第一次請求時,會被編譯成Servlet,然后由這個Servlet處理用戶請求,所以JSP也可以看成是運行時的Servlet。

## 相關問題
***JSP和Servlet的區別與聯系?***
JSP在本質上就是SERVLET,但是兩者的創建方式不一樣.Servlet完全是JAVA程序代碼構成,擅長于流程控制和事務處理,通過Servlet來生成動態網頁很不直觀.JSP由HTML代碼和JSP標簽構成,可以方便地編寫動態網頁.因此在實際應用中采用Servlet來控制業務流程,而采用JSP來生成動態網頁.在struts框架中,JSP位于MVC設計模式的視圖層,而Servlet位于控制層.JSP是Servlet技術的擴展,本質上就是Servlet的簡易方式。JSP編譯后是“類servlet”。Servlet和JSP最主要的不同點在于,Servlet的應用邏輯是在Java文件中,并且完全從表示層中的HTML里分離開來。而JSP是Java和HTML組合成一個擴展名為.jsp的文件。JSP側重于視圖,Servlet主要用于控制邏輯。
# Filter
## Filter接口
**[java]**?[view plain](http://blog.csdn.net/sunxianghuang/article/details/52107376# "view plain")?[copy](http://blog.csdn.net/sunxianghuang/article/details/52107376# "copy")
1. public?interface?Filter?{??
2. ????????//用于完成Filter的初始化??
3. ????public?void?init(FilterConfig?filterConfig)?throws?ServletException;??
4. ????//實現過濾功能??
5. ????????public?void?doFilter?(?ServletRequest?request,?ServletResponse?response,???
6. FilterChain?chain?)?throws?IOException,?ServletException;??
7. ????????//用于銷毀Filter前,完成某些資源的回收??
8. ????public?void?destroy();??
9. }??
## Filter生命周期
web.xml 中聲明的每個 filter 在每個虛擬機中僅僅只有一個實例。
??????? (1) 加載和實例化
??????? Web 容器啟動時,即會根據 web.xml 中聲明的 filter 順序依次實例化這些 filter。
??????? (2) 初始化
??????? Web 容器調用 init(FilterConfig) 來初始化過濾器。容器在調用該方法時,向過濾器傳遞 FilterConfig 對象,FilterConfig 的用法和 ServletConfig 類似。利用 FilterConfig 對象可以得到 ServletContext 對象,以及在 web.xml 中配置的過濾器的初始化參數。在這個方法中,可以拋出 ServletException 異常,通知容器該過濾器不能正常工作。此時的 Web 容器啟動失敗,整個應用程序不能夠被訪問。實例化和初始化的操作只會在容器啟動時執行,而且只會執行一次。
??????? (3) doFilter
??????? doFilter 方法類似于 Servlet 接口的 service 方法。當客戶端請求目標資源的時候,容器會篩選出符合 filter-mapping 中的 url-pattern 的 filter,并按照聲明 filter-mapping 的順序依次調用這些 filter 的 doFilter 方法。在這個鏈式調用過程中,可以調用 chain.doFilter(ServletRequest, ServletResponse) 將請求傳給下一個過濾器(或目標資源),也可以直接向客戶端返回響應信息,或者利用 RequestDispatcher 的 forward 和 include 方法,以及 HttpServletResponse 的 sendRedirect 方法將請求轉向到其它資源。需要注意的是,這個方法的請求和響應參數的類型是 ServletRequest? 和 ServletResponse,也就是說,過濾器的使用并不依賴于具體的協議。
??????? (4) 銷毀
??????? Web 容器調用 destroy 方法指示過濾器的生命周期結束。在這個方法中,可以釋放過濾器使用的資源。
## Filter運行原理


## Filter應用場景
***1、統一POST請求中文字符編碼的過濾器?
2、控制瀏覽器緩存頁面中的靜態資源的過濾器***
有些動態頁面中引用了一些圖片或css文件以修飾頁面效果,這些圖片和css文件經常是不變化的,所以為減輕服務器的壓力,可以使用filter控制瀏覽器緩存這些文件,以提升服務器的性能。
***3、使用Filter實現URL級別的權限認證***
在實際開發中我們經常把一些執行敏感操作的servlet映射到一些特殊目錄中,并用filter把這些特殊目錄保護起來,限制只能擁有相應訪問權限的用戶才能訪問這些目錄下的資源。從而在我們系統中實現一種URL級別的權限功能。
***4、實現用戶自動登陸***
首先,在用戶登陸成功后,發送一個名稱為user的cookie給客戶端,cookie的值為用戶名和md5加密后的密碼。編寫一個AutoLoginFilter,這個filter檢查用戶是否帶有名稱為user的cookie,如果有,則調用dao查詢cookie的用戶名和密碼是否和數據庫匹配,匹配則向session中存入user對象(即用戶登陸標記),以實現程序完成自動登陸。
## Filter應用實例
與開發 Servlet 不同的是,Filter 接口并沒有相應的實現類可供繼承,要開發過濾器,只能直接實現 Filer 接口。
此過濾器用來解決全站中文亂碼問題:設置統一的字符編碼集
**[java]**?[view plain](http://blog.csdn.net/sunxianghuang/article/details/52107376# "view plain")?[copy](http://blog.csdn.net/sunxianghuang/article/details/52107376# "copy")
1. public?class?CharacterEncodingFilter?implements?Filter?{??
2. ???
3. ?????private?FilterConfig?filterConfig?=?null;??
4. ?????//設置默認的字符編碼??
5. ?????private?String?defaultCharset?=?"UTF-";??
6. ???
7. ?????public?void?doFilter(ServletRequest?req,?ServletResponse?resp,??
8. ?????????????FilterChain?chain)?throws?IOException,?ServletException?{??
9. ???????????
10. ?????????HttpServletRequest?request?=?(HttpServletRequest)?req;??
11. ?????????HttpServletResponse?response?=?(HttpServletResponse)?resp;??
12. ?????????String?charset?=?filterConfig.getInitParameter("charset");??
13. ?????????if(charset==null){??
14. ?????????????charset?=?defaultCharset;??
15. ?????????}??
16. ?????????request.setCharacterEncoding(charset);??
17. ?????????response.setCharacterEncoding(charset);??
18. ?????????response.setContentType("text/html;charset="+charset);??
19. ???????????
20. ?????????MyCharacterEncodingRequest?requestWrapper?=?new?MyCharacterEncodingRequest(request);??
21. ?????????chain.doFilter(requestWrapper,?response);??
22. ?????}??
23. ???
24. ?????public?void?init(FilterConfig?filterConfig)?throws?ServletException?{??
25. ?????????//得到過濾器的初始化配置信息??
26. ?????????this.filterConfig?=?filterConfig;??
27. ?????}??
28. ???????
29. ?????public?void?destroy()?{??
30. ???
31. ?????}??
32. ?}??
# Listener
當Web應用在Web容器中運行時,Web應用內部會不斷地發生各種事件:如Web應用的啟動和停止、用戶Session的開始和結束等,通常這些Web事件對開發者是透明的。Listener(監聽器)是觀察者模式的應用,通過方法回調來實現。
## Listener生命周期
Listener在當web容器啟動的時候,去讀取每個web應用的web.xml配置文件,當配置文件中配有filter和listener時,web容器實例化listener,listener是當某個事件發生時,調用它特定方法,如HttpSessionListener,當創建一個session時會調用它的sessionCreated()方法,當servlet容器關閉或者重新加載web應用時lister對象被銷毀。
## Listener分類
不同功能的Listener?需要實現不同的?Listener ?接口,一個Listener也可以實現多個接口,這樣就可以多種功能的監聽器一起工作。常用監聽器:
1)監聽?Session、request、context 的創建于銷毀,分別為 ?
HttpSessionLister、ServletContextListener、ServletRequestListener
2)監聽對象屬性變化,分別為:
HttpSessionAttributeLister、ServletContextAttributeListener、ServletRequestAttributeListener
## Listener應用
***1、利用HttpSessionLister,統計當前在線人數。***
**[java]**?[view plain](http://blog.csdn.net/sunxianghuang/article/details/52107376# "view plain")?[copy](http://blog.csdn.net/sunxianghuang/article/details/52107376# "copy")
1. public?class?OnLineCountListener?implements?HttpSessionListener?{??
2. ??
3. ????@Override??
4. ????public?void?sessionCreated(HttpSessionEvent?se)?{??
5. ????????ServletContext?context?=?se.getSession().getServletContext();??
6. ????????Integer?onLineCount?=?(Integer)?context.getAttribute("onLineCount");??
7. ????????if?(onLineCount?==?null)?{??
8. ????????????context.setAttribute("onLineCount",?1);??
9. ????????}?else?{??
10. ????????????onLineCount++;??
11. ????????????context.setAttribute("onLineCount",?onLineCount);??
12. ????????}??
13. ????}??
14. ??
15. ????@Override??
16. ????public?void?sessionDestroyed(HttpSessionEvent?se)?{??
17. ????????ServletContext?context?=?se.getSession().getServletContext();??
18. ????????Integer?onLineCount?=?(Integer)?context.getAttribute("onLineCount");??
19. ????????if?(onLineCount?==?null)?{??
20. ????????????context.setAttribute("onLineCount",?1);??
21. ????????}?else?{??
22. ????????????onLineCount--;??
23. ????????????context.setAttribute("onLineCount",?onLineCount);??
24. ????????}??
25. ????}??
26. }??
***2、自定義Session掃描器***
當一個Web應用創建的Session很多時,為了避免Session占用太多的內存,我們可以選擇手動將這些內存中的session銷毀,那么此時也可以借助監聽器技術來實現。
參考
http://zachary-guo.iteye.com/blog/640889
http://www.cnblogs.com/xdp-gacl/p/3965508.html
- 誰能舉個通俗易懂的例子告訴我IAAS,SAAS,PAAS的區別?
- 服務器與容器
- 常見NIO框架
- Nginx/Apache 和Apache Tomcat 的區別
- tomcat結合nginx使用小結
- java nio框架netty 與tomcat的關系
- Nginx、Lighttpd與Apache的區別
- Apache vs Lighttpd vs Nginx對比
- 數據庫
- mybatis
- MyBatis傳入多個參數的問題
- MS
- JMS(Java消息服務)入門教程
- ActiveMQ
- JMS簡介與ActiveMQ實戰
- JMS-使用消息隊列優化網站性能
- 深入淺出JMS(一)--JMS基本概念
- 深入淺出JMS(二)--ActiveMQ簡單介紹以及安裝
- 深入淺出JMS(三)--ActiveMQ簡單的HelloWorld實例
- RabbitMq、ActiveMq、ZeroMq、kafka之間的比較,資料匯總
- kafka
- zookeeper
- 集群與負載
- 單機到分布式集群
- 日志
- 從Log4j遷移到LogBack的理由
- 角色權限
- shiro
- Shiro的認證和權限控制
- Spring 整合 Apache Shiro 實現各等級的權限管理
- 安全
- basic
- Servlet、Filter、Listener深入理解
- filter與servlet的比較
- Servlet Filter