Servlet 規范擴展 ------ 監聽器介面
1、介紹:
1)一組來自于 Servlet 規范下的介面,共有8個介面,
2)監聽器介面需要由開發人員親自實作,Http服務器提供 jar 包并沒有對應的實作類,
3)監聽器介面用于監控【作用域物件生命周期變化時刻】以及【作用域物件共享資料變化時刻】,
2、作用域物件:
1)Servlet 規范中,在服務端記憶體中可以在某些條件下為兩個 Servlet 之間提供資料共享方案的物件,被稱為【作用域物件】,
2)Servlet 規范下作用域物件:
ServletContext 【全域作用域物件】
HttpSession 【會話作用域物件】
HttpServletRequest 【請求作用域物件】
3、監聽器介面實作類開發規范(三步):
1)根據監聽的實際情況,選擇對應監聽器介面進行實作;
2)重寫監聽器介面宣告【監聽事件處理方法】;
3)在web.xml檔案將監聽器介面實作類注冊到 Http 服務器,
4、ServletContextListener 介面:
1)作用:通過介面合法的檢測全域作用域物件被初始化時刻以及被銷毀時刻,
2)監聽事件處理方法:
public void contextInitlized(){...} //全域作用域物件被 Http 服務器初始化(創建)時被呼叫
public void contextDestory(){...} //全域作用域物件被 Http 服務器銷毀時被呼叫
5、ServletContextAttributeListener 介面:
1)作用:通過這個介面合法的檢測全域作用域物件共享資料變化時刻,
2)監聽事件處理方法:
public void contextAdd(){...} //在全域作用域物件添加共享資料時,觸發
public void contextReplaced(){...} //在全域作用域物件更新共享資料時,觸發
public void contextRemove(){...} //在全域作用域物件洗掉共享資料時,觸發
實作監聽器介面 --- 優化在線考試管理系統
- 在線考試管理系統(未優化) 源代碼:【JavaWeb-Servlet】編程(1)--- JavaSE+MySQL+JDBC+Servlet 實作在線考試管理系統(用戶資訊管理模塊)
- 網站預覽:

- 實作查詢用戶資訊的代碼塊:
package com.burnyouth.controller;
import com.burnyouth.dao.UserDao;
import com.burnyouth.entity.User;
import jakarta.servlet.*;
import jakarta.servlet.http.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Date;
import java.util.List;
public class UserFindServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
UserDao dao = new UserDao();
PrintWriter out = null;
//1、【呼叫Dao】將查詢命令推送到資料庫服務器上,得到所有用戶資訊【List】
Date startTime = new Date();//通過Date類,看看遍歷用戶資訊會消耗多少時間?
List<User> userList = dao.findAll();
Date endTime = new Date();
System.out.println("執行遍歷用戶資訊耗費時間:"+(endTime.getTime()-startTime.getTime())+"毫秒");
//2、【呼叫回應物件】將用戶資訊結合<table>標簽命令以二進制形式寫入到回應體
//設定回應頭content-type屬性
response.setContentType("text/html;charset=utf-8");
out = response.getWriter();
out.print("<table border='2'>");
out.print("<tr>");
out.print("<td>用戶編號</td>");
out.print("<td>用戶姓名</td>");
out.print("<td>用戶密碼</td>");
out.print("<td>用戶性別</td>");
out.print("<td>用戶郵箱</td>");
out.print("<td>操作</td>");
out.print("</tr>");
for (User user : userList) {
out.print("<tr>");
out.print("<td>" + user.getUserId() + "</td>");
out.print("<td>" + user.getUserName() + "</td>");
out.print("<td>******</td>");
out.print("<td>" + user.getSex() + "</td>");
out.print("<td>" + user.getEmail() + "</td>");
out.print("<td><a href='https://www.cnblogs.com/myWeb/user/delete?userId="+user.getUserId()+"'>" +
"洗掉用戶</a></td>");
out.print("</tr>");
}
out.print("</table>");
}
}
- 執行多次查詢代碼,IDEA 控制臺:

- 問題描述:
可以看到遍歷一次用戶資訊時長基本穩定在 13 ~ 18 毫秒之間,如果這個管理系統的使用者只有一個人,當然用戶的體驗是非常好的,但這是不現實的,而當系統同時使用的用戶人數達到幾萬時,有的用戶就可能需要等待幾分鐘的時間,那用戶體驗感就非常差了,所以我們就需要應用適合的優化方案來提高系統的運行速度,而監聽器介面 就剛好是一種優化方案,
通過查閱資料發現,遍歷用戶資訊大部分時間都耗費在了 Connection 通道的建立上,所以我們可以在服務器啟動時,就預準備創建幾個 Connection 介面,這樣在執行遍歷用戶資訊代碼的時候,就不需要再創建 Connection 通道了,
- 優化代碼:
com.burnyouth.listener.Onelistener(監聽器):
package com.burnyouth.listener;
import com.burnyouth.util.JdbcUtil;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class Onelistener implements ServletContextListener {
/**
* 在全域作用域物件創建時,創建 10 個 Connection 通道
* @param sce 獲取全域作用域物件
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
//裝10個通道的集合
Map connections = new HashMap();
//獲取全域作用域物件
ServletContext application = sce.getServletContext();
for (int i = 0; i < 10; i++) {
try {
Connection connection = JdbcUtil.getConnection();
//將創建好的通道放到集合里,并打上 true 標記(代表此通道為空閑狀態)
connections.put(connection, true);
} catch (SQLException throwables) {
throwables.printStackTrace();
}
}
//最后將集合上交給全域作用域物件
application.setAttribute("connections", connections);
}
/**
* 全域作用域物件銷毀時,同時關閉 10 個 Connection 通道
* @param sce 獲取全域作用域物件
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
//獲取全域作用域物件
ServletContext application = sce.getServletContext();
//將集合取出來
Map map = (Map) application.getAttribute("connections");
//將集合中的通道一個個地關閉
Iterator it = map.keySet().iterator();
while (it.hasNext()) {
Connection connection = (Connection) it.next();
if (connection != null) {
JdbcUtil.close(connection,null,null);
}
}
}
}
xml (僅展示將監聽器注冊到服務器的代碼):
<listener>
<listener-class>com.burnyouth.listener.Onelistener</listener-class>
</listener>
com.burnyouth.util.JdbcUtil(利用方法多載,添加了新的 getConnection() ,close() ):
package com.burnyouth.util;
import jakarta.servlet.ServletContext;
import jakarta.servlet.http.HttpServletRequest;
import java.sql.*;
import java.util.Iterator;
import java.util.Map;
/**
* JDBC工具類
*/
public class JdbcUtil {
/**
* 工具類的構造方法都應該是私有的
* 因為工具類是需要頻繁使用的,所以我們要避免代碼的重復書寫
* 將工具類方法都設為靜態的,再將構造方法私有化(這樣想new都new不出來),直接采用類名呼叫
*/
//靜態代碼塊在類加載時執行,并且只執行一次
static {
try {
Class.forName("com.mysql.cj.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private JdbcUtil() {
}
/**
* 獲取資料庫連接物件
*
* @return 連接
* @throws SQLException
*/
//因為此方法是被呼叫的方法,所以出現例外直接上拋就行
public static Connection getConnection() throws SQLException {
return DriverManager.getConnection("jdbc:mysql://localhost:3306/burning_youth"
, "root", "888");
}
/**
* 獲取服務器在啟動時,就創建好的 Connection 通道
* @param request 網站的請求物件
* @return Map集合中空閑的 Connection 通道
* @throws SQLException
*/
public static Connection getConnection(HttpServletRequest request) throws SQLException {
//獲取全域作用域物件:
ServletContext application = request.getServletContext();
//獲取集合
Map connections = (Map) application.getAttribute("connections");
Connection connection = null;
//獲取集合中空閑狀態的 Connection 通道
Iterator it = connections.keySet().iterator();
while (it.hasNext()) {
connection = (Connection) it.next();
//查看通道狀態
boolean flag = (boolean) connections.get(connection);
if (flag == true) {
//找到空閑狀態的通道后,更改狀態
connections.put(connection,false);
//結束回圈
break;
}
}
return connection;
}
/**
* 關閉資源
*
* @param connection 連接資源
* @param statement 資料庫操作物件
* @param resultSet 結果集
*/
public static void close(Connection connection, Statement statement, ResultSet resultSet) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* 關閉資源,注意通道不要關閉,將狀態更改為空閑狀態即可
* @param connection
* @param statement
* @param resultSet
* @param request 網站的請求物件
*/
public static void close(Connection connection, Statement statement,
ResultSet resultSet,HttpServletRequest request) {
if (resultSet != null) {
try {
resultSet.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
if (statement != null) {
try {
statement.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
//獲取全域作用域物件
ServletContext application = request.getServletContext();
//獲取集合
Map connections = (Map) application.getAttribute("connections");
//更改通道狀態
connections.put(connection,true);
}
}
com.burnyouth.dao.UserDao(僅展示優化后的 findAll() 代碼):
public List findAll(HttpServletRequest request) {
Connection connection = null;
PreparedStatement ps = null;
ResultSet resultSet = null;
List userList = new ArrayList();
try {
//呼叫新方法
connection = JdbcUtil.getConnection(request);
String sql = "select * from user";
ps = connection.prepareStatement(sql);
resultSet = ps.executeQuery();
while (resultSet.next()) {
Integer userId = resultSet.getInt("userId");
String userName = resultSet.getString("userName");
String password = resultSet.getString("password");
String sex = resultSet.getString("sex");
String email = resultSet.getString("email");
User user = new User(userId, userName, password, sex, email);
userList.add(user);
}
} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
//呼叫新方法
JdbcUtil.close(connection, ps, resultSet,request);
}
return userList;
}
- 優化效果:效果有點頂了,快10倍不止啊 !!! (?′?`?)

隨筆:
1、設計模式六大原則之一的開閉原則,禁止我們修改原來寫好的代碼,所以當我們優化代碼功能時,并沒有直接修改原來的方法體,而是在類中通過方法多載機制,寫入了優化后的代碼,
2、向一個專案中添加功能或者優化功能時,如果涉及到方法之間的呼叫問題,注意由根到頂的邏輯,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/444361.html
標籤:其他
下一篇:Struts 2 學習筆記
