JBuilder2005Servlet開發之自啟動
Servlet和JSP的一個重大的區別即是Servlet可以通過web.xml文件的配置讓Servlet在Web容器啟動時就自動啟動Servlet。可以利用Servlet的這個特性不變化的數據事先加載到Web應用服務器中以便緩存使用。
假設,我們系統的用戶在系統部署前就已經創建好,以后不常發生變化,那么我們可以在Web應用程序啟動時就將其下載緩存到Web應用服務器內存中,如果用戶發生變化可以手工調用這個Servlet進行刷新。下面我們就通過Servlet向導創建這個UserCacheServlet,它在Web容器啟動時自動下載并緩存系統所有用戶Id和用戶名:
1.啟動創建Servlet向導,填寫Servlet名字
通過File->New...->Web->雙擊Standard Servlet圖標啟動創建Servlet向導的第一步,如下圖所示:
在Class name中填入Servlet的名字:UserCacheServlet,在Package中填入bookstore.servlet作為包名。按Next到下一步。
2.選擇Servlet所要實現的方法。
我們在前面已經介紹了Servlet通過不同的doXxx()方法的響應HTTP請求方式,你可以在向導的第2步選擇需要定義哪些doXxx()方法。默認情況下doGet()方法被勾選,即通過HTTP GET請求方式訪問Servlet。通過帶參的URL訪問Servlet時,Servlet就用doGet()方法響應這個請求。由于我們只是假設用戶數據不常變動,并不是說永遠不變動,所以我們在Web容器初始化時,希望通過UserCacheServlet自動加載用戶數據到緩存中,當數據庫表T_USER的用戶數據發生變動時,我們可以手工調用UserCacheServlet,讓其刷新緩存中的用戶數據。
Web容器啟動時自動初始化UserCacheServlet,此時init()方法被調用,我們可以通過init()方法加載用戶數據,當用戶通過URL請求刷新用戶數據時,UserCacheServlet通過doGet()方法響應這個HTTP GET請求。也就是說,我們需要實現doGet()方法,所以我們接受向導的默認設置,如下圖所示:
按Next跳過第3步到向導的第4步。
3.指定訪問Servlet的路徑
·Name:usercacheservlet,Servlet在web.xml配置文件中所取的名字
·URL pattern:/usercacheservlet,訪問這個Servlet的匹配路徑。指定這個訪問路徑后,假設Web應用程序部署在http://localhost:8080/webModule下,則通過http://localhost:8080/webModule/usercacheservlet訪問servlet。
直接按Finish創建Servlet。
打開web.xml文件,你可以找到關于UserCacheServlet聲明和訪問的部署描述信息:
·<servlet>節點:描述servlet的名字及類名。
·<servlet-mapping>節點:描述servlet訪問匹配路徑。
雙擊工程窗格資源樹的webModule節點,JBuilder在內容窗格中打開用于編輯web.xml文件的Web模塊DD編輯器(Web Module DD editor),此時結構窗格顯示出web.xml文件的結構,如下圖所示:
帶
圖標的節點表示已經有配置內容,而未帶
圖標的節點表示暫時還沒有對應的配置內容。我們展開Servlets節點,定位到usercacheservlet并雙擊這個節點,DD編輯器調整界面對usercacheservlet這個Servlet進行配置,如下圖所示:
Servlet可以在Web容器啟動時,自動初始化。假設有多個Servlet都需要自動初始化,則可以通過web.xml的<load-on-startup>設置啟動的次序。我們在DD編輯器將Load on startup值設為2, 這樣UserCacheServlet將在Web容器啟動后,排在順序2初始化。
一些系統所用的Servlet,由于是Web開始服務的基礎必須在順序1初化,所以我們開發的Servlet最好在順序2或順序3初始化。Servlet初始化時,init()方法被調用。在進行這樣的設置后web.xml將包含以下粗體所示的配置信息。
代碼清單 1 web.xml有關UserCacheServlet的描述信息
注意:
當刪除UserCacheServlet后,Servlet在web.xml所對應的部署描述信息并不會一起刪除,你必須手工刪除。
在init()初始化方法中利用UserList.fillUser()方法從數據庫中下載并緩存用戶記錄信息,在doGet()方法中也引用了UserList.fillUser(),用戶通過URL訪問UserCacheServlet時,doGet()方法被調用,刷新緩存用戶數據,并顯示"刷新成功"提示,其代碼如下所示:
代碼清單 2 UserCacheServlet.java
當然,我們要對《JBuilder 2005實戰JSP開發》專題中創建的UserList.java代碼進行更改,定義fillUser()方法以供UserCacheServlet.java調用,此外,還需要調整原getUserListHTML()方法,如下所示:
代碼清單 3 調整后的UserList.java代碼
首先,我們在第9行定義了一個靜態的userMap對象用以緩存用戶信息,這個Map以userId為鍵保存UserName的值。第11'49行的靜態fillUser()方法從數據庫中獲取用戶的信息填充到userMap中。當用戶訪問login.jsp生成用戶下拉框時,用戶數據直接從userMap緩存中讀取,而不再從數據庫中讀取,你可以從第54'56行的代碼中看到這種獲取用戶數據方式的改變。當添加或刪除用戶時,可以通過http://localhost:8080/webModule/usercacheservlet刷新緩存數據。
實戰經驗:
假設,我們系統的用戶在系統部署前就已經創建好,以后不常發生變化,那么我們可以在Web應用程序啟動時就將其下載緩存到Web應用服務器內存中,如果用戶發生變化可以手工調用這個Servlet進行刷新。下面我們就通過Servlet向導創建這個UserCacheServlet,它在Web容器啟動時自動下載并緩存系統所有用戶Id和用戶名:
1.啟動創建Servlet向導,填寫Servlet名字
通過File->New...->Web->雙擊Standard Servlet圖標啟動創建Servlet向導的第一步,如下圖所示:
![]() 圖 2填寫Servlet名字 |
在Class name中填入Servlet的名字:UserCacheServlet,在Package中填入bookstore.servlet作為包名。按Next到下一步。
2.選擇Servlet所要實現的方法。
我們在前面已經介紹了Servlet通過不同的doXxx()方法的響應HTTP請求方式,你可以在向導的第2步選擇需要定義哪些doXxx()方法。默認情況下doGet()方法被勾選,即通過HTTP GET請求方式訪問Servlet。通過帶參的URL訪問Servlet時,Servlet就用doGet()方法響應這個請求。由于我們只是假設用戶數據不常變動,并不是說永遠不變動,所以我們在Web容器初始化時,希望通過UserCacheServlet自動加載用戶數據到緩存中,當數據庫表T_USER的用戶數據發生變動時,我們可以手工調用UserCacheServlet,讓其刷新緩存中的用戶數據。
Web容器啟動時自動初始化UserCacheServlet,此時init()方法被調用,我們可以通過init()方法加載用戶數據,當用戶通過URL請求刷新用戶數據時,UserCacheServlet通過doGet()方法響應這個HTTP GET請求。也就是說,我們需要實現doGet()方法,所以我們接受向導的默認設置,如下圖所示:
![]() 圖 3 選擇需要覆蓋的Servlet響應方法 |
按Next跳過第3步到向導的第4步。
3.指定訪問Servlet的路徑
![]() 圖 4 指定Servlet訪問路徑 |
·Name:usercacheservlet,Servlet在web.xml配置文件中所取的名字
·URL pattern:/usercacheservlet,訪問這個Servlet的匹配路徑。指定這個訪問路徑后,假設Web應用程序部署在http://localhost:8080/webModule下,則通過http://localhost:8080/webModule/usercacheservlet訪問servlet。
直接按Finish創建Servlet。
打開web.xml文件,你可以找到關于UserCacheServlet聲明和訪問的部署描述信息:
·<servlet>節點:描述servlet的名字及類名。
·<servlet-mapping>節點:描述servlet訪問匹配路徑。
雙擊工程窗格資源樹的webModule節點,JBuilder在內容窗格中打開用于編輯web.xml文件的Web模塊DD編輯器(Web Module DD editor),此時結構窗格顯示出web.xml文件的結構,如下圖所示:
![]() 圖 5 結構窗格的web.xml文件結構樹 |
帶
圖標的節點表示已經有配置內容,而未帶
圖標的節點表示暫時還沒有對應的配置內容。我們展開Servlets節點,定位到usercacheservlet并雙擊這個節點,DD編輯器調整界面對usercacheservlet這個Servlet進行配置,如下圖所示:![]() 圖 6 DD編輯器 |
Servlet可以在Web容器啟動時,自動初始化。假設有多個Servlet都需要自動初始化,則可以通過web.xml的<load-on-startup>設置啟動的次序。我們在DD編輯器將Load on startup值設為2, 這樣UserCacheServlet將在Web容器啟動后,排在順序2初始化。
一些系統所用的Servlet,由于是Web開始服務的基礎必須在順序1初化,所以我們開發的Servlet最好在順序2或順序3初始化。Servlet初始化時,init()方法被調用。在進行這樣的設置后web.xml將包含以下粗體所示的配置信息。
代碼清單 1 web.xml有關UserCacheServlet的描述信息
| 1. <web-app> 2. … 3. <servlet> 4. <servlet-name>usercacheservlet</servlet-name> 5. <servlet-class>bookstore.servlet.UserCacheServlet</servlet-class> 6. <load-on-startup>2</load-on-startup> 7. </servlet> 8. <servlet-mapping> 9. <servlet-name>usercacheservlet</servlet-name> 10. <url-pattern>/usercacheservlet</url-pattern> 11. </servlet-mapping> 12. … 13. </web-app> |
注意:
當刪除UserCacheServlet后,Servlet在web.xml所對應的部署描述信息并不會一起刪除,你必須手工刪除。
在init()初始化方法中利用UserList.fillUser()方法從數據庫中下載并緩存用戶記錄信息,在doGet()方法中也引用了UserList.fillUser(),用戶通過URL訪問UserCacheServlet時,doGet()方法被調用,刷新緩存用戶數據,并顯示"刷新成功"提示,其代碼如下所示:
代碼清單 2 UserCacheServlet.java
| 1. package bookstore.servlet; 2. 3. import javax.servlet.*; 4. import javax.servlet.http.*; 5. import java.io.*; 6. import bookstore.UserList; 7. 8. public class UserCacheServlet 9. extends HttpServlet 10. { 11. private static final String CONTENT_TYPE = "text/html; charset=GBK"; 12. 13. //Initialize global variables 14. public void init() 15. throws ServletException 16. { 17. UserList.fillUser();//Web容器啟動后調用 18. } 19. 20. //Process the HTTP Get request 21. public void doGet(HttpServletRequest request, HttpServletResponse response) 22. throws ServletException, IOException 23. { 24. UserList.fillUser();//刷新用戶數據 25. response.setContentType(CONTENT_TYPE); 26. PrintWriter out = response.getWriter(); 27. out.println("<html>"); 28. out.println("<head><title>UserCacheServlet</title></head>"); 29. out.println("<body bgcolor="#ffffff">"); 30. out.println("刷新成功!"); 31. out.println("</body>"); 32. out.println("</html>"); 33. out.close(); 34. } |
當然,我們要對《JBuilder 2005實戰JSP開發》專題中創建的UserList.java代碼進行更改,定義fillUser()方法以供UserCacheServlet.java調用,此外,還需要調整原getUserListHTML()方法,如下所示:
代碼清單 3 調整后的UserList.java代碼
| 2. package bookstore; 3. 4. import java.sql.*; 5. import java.util.*; 6. 7. public class UserList 8. { 9. private static Map userMap;//用戶ID和用戶名的Map 10. //將用戶數據緩存到Map中 11. public static void fillUser() 12. { 13. if (userMap == null) 14. { 15. userMap = new HashMap(); 16. } else 17. { 18. userMap.clear(); 19. } 20. Connection conn = null; 21. StringBuffer sBuf = new StringBuffer(); 22. try 23. { 24. conn = DBConnection.getConnection(); 25. PreparedStatement pStat = conn.prepareStatement( 26. "select USER_ID,USER_NAME from T_USER"); 27. ResultSet rs = pStat.executeQuery(); 28. while (rs.next()) 29. { 30. userMap.put(rs.getString(1), rs.getString(2)); 31. } 32. } catch (SQLException ex) 33. { 34. ex.printStackTrace(); 35. } finally 36. { 37. try 38. { 39. if (conn != null) 40. { 41. conn.close(); 42. conn = null; 43. } 44. } catch (SQLException ex1) 45. { 46. ex1.printStackTrace(); 47. } 48. } 49. } 50. 51. //獲取HTML下拉框的用戶列表代碼 52. public static String getUserListHTML() 53. { 54. StringBuffer sBuf = new StringBuffer(); 55. Set set = userMap.keySet(); 56. Iterator iter = set.iterator(); 57. while (iter.hasNext()) 58. { 59. Object item = (Object) iter.next(); 60. sBuf.append("<option value=’" + item + "’>" + 61. userMap.get(item) + "</option>"); 62. } 63. return sBuf.toString(); 64. } 65. } |
首先,我們在第9行定義了一個靜態的userMap對象用以緩存用戶信息,這個Map以userId為鍵保存UserName的值。第11'49行的靜態fillUser()方法從數據庫中獲取用戶的信息填充到userMap中。當用戶訪問login.jsp生成用戶下拉框時,用戶數據直接從userMap緩存中讀取,而不再從數據庫中讀取,你可以從第54'56行的代碼中看到這種獲取用戶數據方式的改變。當添加或刪除用戶時,可以通過http://localhost:8080/webModule/usercacheservlet刷新緩存數據。
實戰經驗:
| 使用緩存保存不常變動而頻繁訪問的數據是提高系統性能一個很重要的途徑。如果你的Web服務器沒有實現集群,刷新緩存數據非常簡單,只需通過一個Servlet在發生數據變動時刷新就可以了。如果Web服務器使用了集群,問題就變得復雜了,因為每一臺Web服務器的JVM是獨立的,所以每臺Web服務器都有一份獨立的緩存數據,當數據發生變動時,必須對每臺Web服務器中對緩存進行刷新。這里有兩種解決方案,其一是使用獨立于Web服務器的專用共享資源機器緩存數據,集群中所有的Web服務器通過JNDI等方式訪問緩存數據。另外的一種方法則是通過同步機制在任意一臺服務器緩存數據發生變動時同步到集群中的其他機器上。Apache的Turbine項目的JCS子項目專門為解決這一企業級的問題而開發,你可以通過http://jakarta.apache.org/jcs/index.html了解JCS的更多內容。 |




