- Sản phẩm & Dịch vụSản phẩm & Dịch vụ
- Giải phápGiải pháp
- Bảng giáBảng giá
- Công tyCông ty
- Tài liệuTài liệu
vi
vi
Chuyên mục với các bài viết hướng dẫn, nghiên cứu và phân tích chi tiết về kỹ thuật, các xu hướng công nghệ mới nhất dành cho lập trình viên.
Web Developer
I’m passionate about web development and sharing my insights through articles, with over 8 years of experience. I hope these sharings inspire you and help build a strong web development community. @#@ Tôi đam mê phát triển web và chia sẻ những hiểu biết của mình thông qua các bài viết, với hơn 8 năm kinh nghiệm. Tôi hy vọng những chia sẻ này sẽ truyền cảm hứng cho các bạn và giúp xây dựng một cộng đồng phát triển web mạnh mẽ.
Thảo luận (0)
Đăng nhập để thảo luận
ServletContextListener là một trong số nhiều Servlet Listener (trình theo dõi sự kiện trong Servlet) hiện có.

Trong hướng dẫn này, chúng ta sẽ tìm hiểu về Servlet Listener, lợi ích của chúng, một số tác vụ phổ biến có thể thực hiện với Listener, các interface Listener của servlet API và các đối tượng Event. Cuối cùng, ta sẽ tạo một dự án web đơn giản để minh họa cách triển khai các Listener thường dùng cho ServletContext, Session và ServletRequest.
Bằng cách sử dụng ServletContext, ta có thể tạo một attribute (thuộc tính) với phạm vi toàn ứng dụng để tất cả các servlet khác đều truy cập được. Tuy nhiên, trong file mô tả triển khai (web.xml), ta chỉ có thể khởi tạo các khởi tạo tham số của ServletContext dưới dạng chuỗi String. Vậy nếu ứng dụng chủ yếu làm việc với cơ sở dữ liệu và ta muốn đặt một attribute trong ServletContext cho các kết nối cơ sở dữ liệu thì sao?
Nếu ứng dụng chỉ có một truy cập vào duy nhất (ví dụ: trang đăng nhập), ta có thể thực hiện việc này trong request đầu tiên cho servlet. Nhưng nếu có nhiều điểm vào, việc lặp lại logic này ở khắp nơi sẽ dẫn đến trùng lặp code. Hơn nữa, nếu cơ sở dữ liệu gặp sự cố hoặc cấu hình sai, ta sẽ không phát hiện vấn đề ra cho đến khi có request đầu tiên từ client.
Để giải quyết những tình huống này, servlet API cung cấp các interface Listener. Ta có thể triển khai và cấu hình các Listener này để lắng nghe một event và thực hiện một hành động cụ thể.
Event (sự kiện) là một hành động nào đó xảy ra. Trong thế giới ứng dụng web, event có thể là việc khởi tạo hoặc hủy ứng dụng, một request từ client, tạo/hủy một session, thay đổi attribute trong session, v.v.
Servlet API cung cấp nhiều loại interface Listener khác nhau. Ta có thể triển khai và cấu hình chúng trong web.xml để xử lý tác vụ khi một event cụ thể xảy ra. Ví dụ, với tình huống trên, ta có thể tạo một Listener cho event khởi động ứng dụng. Listener này sẽ đọc các tham số khởi tạo ngữ cảnh, tạo kết nối cơ sở dữ liệu và gán nó vào tham số ngữ cảnh để các tài nguyên khác có thể sử dụng.
Servlet API cung cấp nhiều loại Listener khác nhau cho các loại Event khác nhau. Các interface Listener định nghĩa các phương thức để xử lý một nhóm các event tương tự. Ví dụ, ServletContext Listener lắng nghe event khởi động (startup) và tắt (shutdown) của context.
Mỗi phương thức trong interface Listener đều nhận một đối tượng Event làm tham số đầu vào. Đối tượng Event này đóng vai trò như một lớp vỏ bọc (wrapper), cung cấp đối tượng cụ thể cho Listener.
Servlet API cung cấp các đối tượng event sau:
Servlet API cung cấp các interface Listener sau đây:
Ta có thể dùng annotation @WebListener để khai báo một class là Listener. Tuy nhiên, class này phải triển khai một hoặc nhiều interface Listener. Ta cũng có thể định nghĩa listener trong web.xml như sau:
<listener>
<listener-class>
com.journaldev.listener.AppContextListener
</listener-class>
</listener>
Hãy cùng tạo một ứng dụng web đơn giản để xem cách Servlet Listener hoạt động trong thực tế. Ta sẽ tạo một dự án web động trong Eclipse tên là ServletListenerExample với cấu trúc thư mục như hình bên dưới.

web.xml: Trong file mô tả triển khai, ta sẽ định nghĩa một số tham số khởi tạo ngữ cảnh và cấu hình cho Listener.
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="<https://www.w3.org/2001/XMLSchema-instance>" xmlns="<https://java.sun.com/xml/ns/javaee>" xsi:schemaLocation="<https://java.sun.com/xml/ns/javaee> <https://java.sun.com/xml/ns/javaee/web-app_3_0.xsd>" id="WebApp_ID" version="3.0"> <display-name>ServletListenerExample</display-name><context-param> <param-name>DBUSER</param-name> <param-value>pankaj</param-value> </context-param> <context-param> <param-name>DBPWD</param-name> <param-value>password</param-value> </context-param> <context-param> <param-name>DBURL</param-name> <param-value>jdbc:mysql://localhost/mysql_db</param-value> </context-param>
<listener> <listener-class>com.journaldev.listener.AppContextListener</listener-class> </listener> <listener> <listener-class>com.journaldev.listener.AppContextAttributeListener</listener-class> </listener> <listener> <listener-class>com.journaldev.listener.MySessionListener</listener-class> </listener> <listener> <listener-class>com.journaldev.listener.MyServletRequestListener</listener-class> </listener> </web-app>
DBConnectionManager: Đây là class dùng để kết nối cơ sở dữ liệu. Để cho đơn giản, ta sẽ không cung cấp code kết nối cơ sở dữ liệu thực tế. Ta sẽ đặt đối tượng này làm attribute cho ngữ cảnh servlet.
package com.journaldev.db;import java.sql.Connection;
public class DBConnectionManager {
private String dbURL; private String user; private String password; private Connection con; public DBConnectionManager(String url, String u, String p){ this.dbURL=url; this.user=u; this.password=p; //create db connection now } public Connection getConnection(){ return this.con; } public void closeConnection(){ //close DB connection here }}
MyServlet: Một class servlet đơn giản, nơi ta sẽ làm việc với session, attribute, v.v.
package com.journaldev.servlet;import java.io.IOException; import java.io.PrintWriter;
import javax.servlet.ServletContext; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession;
@WebServlet("/MyServlet") public class MyServlet extends HttpServlet { private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { ServletContext ctx = request.getServletContext(); ctx.setAttribute("User", "Pankaj"); String user = (String) ctx.getAttribute("User"); ctx.removeAttribute("User"); HttpSession session = request.getSession(); session.invalidate(); PrintWriter out = response.getWriter(); out.write("Hi "+user); }}
Bây giờ, ta sẽ triển khai các class Listener. Dưới đây là các class Listener mẫu cho những listener thường dùng nhất: ServletContextListener, ServletContextAttributeListener, ServletRequestListener và HttpSessionListener.
Ta sẽ đọc các tham số khởi tạo của ngữ cảnh servlet để tạo đối tượng DBConnectionManager và gán nó làm thuộc tính cho đối tượng ServletContext.
package com.journaldev.listener;import javax.servlet.ServletContext; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; import javax.servlet.annotation.WebListener;
import com.journaldev.db.DBConnectionManager;
@WebListener public class AppContextListener implements ServletContextListener {
public void contextInitialized(ServletContextEvent servletContextEvent) { ServletContext ctx = servletContextEvent.getServletContext(); String url = ctx.getInitParameter("DBURL"); String u = ctx.getInitParameter("DBUSER"); String p = ctx.getInitParameter("DBPWD"); //create database connection from init parameters and set it to context DBConnectionManager dbManager = new DBConnectionManager(url, u, p); ctx.setAttribute("DBManager", dbManager); System.out.println("Database connection initialized for Application."); } public void contextDestroyed(ServletContextEvent servletContextEvent) { ServletContext ctx = servletContextEvent.getServletContext(); DBConnectionManager dbManager = (DBConnectionManager) ctx.getAttribute("DBManager"); dbManager.closeConnection(); System.out.println("Database connection closed for Application."); }}
Đây là một triển khai đơn giản để log lại event khi một thuộc tính được thêm, xóa hoặc thay thế trong ngữ cảnh servlet.
package com.journaldev.listener;import javax.servlet.ServletContextAttributeEvent; import javax.servlet.ServletContextAttributeListener; import javax.servlet.annotation.WebListener;
@WebListener public class AppContextAttributeListener implements ServletContextAttributeListener {
public void attributeAdded(ServletContextAttributeEvent servletContextAttributeEvent) { System.out.println("ServletContext attribute added::{"+servletContextAttributeEvent.getName()+","+servletContextAttributeEvent.getValue()+"}"); } public void attributeReplaced(ServletContextAttributeEvent servletContextAttributeEvent) { System.out.println("ServletContext attribute replaced::{"+servletContextAttributeEvent.getName()+","+servletContextAttributeEvent.getValue()+"}"); } public void attributeRemoved(ServletContextAttributeEvent servletContextAttributeEvent) { System.out.println("ServletContext attribute removed::{"+servletContextAttributeEvent.getName()+","+servletContextAttributeEvent.getValue()+"}"); }}
Một triển khai đơn giản để log lại event khi một session được tạo hoặc bị hủy.
package com.journaldev.listener;import javax.servlet.annotation.WebListener; import javax.servlet.http.HttpSessionEvent; import javax.servlet.http.HttpSessionListener;
@WebListener public class MySessionListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent sessionEvent) { System.out.println("Session Created:: ID="+sessionEvent.getSession().getId()); } public void sessionDestroyed(HttpSessionEvent sessionEvent) { System.out.println("Session Destroyed:: ID="+sessionEvent.getSession().getId()); }}
Một triển khai đơn giản của interface ServletRequestListener để log địa chỉ IP của ServletRequest khi request được khởi tạo và bị hủy.
package com.journaldev.listener;import javax.servlet.ServletRequest; import javax.servlet.ServletRequestEvent; import javax.servlet.ServletRequestListener; import javax.servlet.annotation.WebListener;
@WebListener public class MyServletRequestListener implements ServletRequestListener {
public void requestDestroyed(ServletRequestEvent servletRequestEvent) { ServletRequest servletRequest = servletRequestEvent.getServletRequest(); System.out.println("ServletRequest destroyed. Remote IP="+servletRequest.getRemoteAddr()); } public void requestInitialized(ServletRequestEvent servletRequestEvent) { ServletRequest servletRequest = servletRequestEvent.getServletRequest(); System.out.println("ServletRequest initialized. Remote IP="+servletRequest.getRemoteAddr()); }}
Bây giờ, khi ta deploy ứng dụng và truy cập MyServlet trên trình duyệt bằng URL http://localhost:8080/ServletListenerExample/MyServlet, ta sẽ thấy các dòng log sau trong file log của server.
ServletContext attribute added::{DBManager,com.journaldev.db.DBConnectionManager@4def3d1b}
Database connection initialized for Application.
ServletContext attribute added::{org.apache.jasper.compiler.TldLocationsCache,org.apache.jasper.compiler.TldLocationsCache@1594df96}
ServletRequest initialized. Remote IP=0:0:0:0:0:0:0:1%0
ServletContext attribute added::{User,Pankaj}
ServletContext attribute removed::{User,Pankaj}
Session Created:: ID=8805E7AE4CCCF98AFD60142A6B300CD6
Session Destroyed:: ID=8805E7AE4CCCF98AFD60142A6B300CD6
ServletRequest destroyed. Remote IP=0:0:0:0:0:0:0:1%0
ServletRequest initialized. Remote IP=0:0:0:0:0:0:0:1%0
ServletContext attribute added::{User,Pankaj}
ServletContext attribute removed::{User,Pankaj}
Session Created:: ID=88A7A1388AB96F611840886012A4475F
Session Destroyed:: ID=88A7A1388AB96F611840886012A4475F
ServletRequest destroyed. Remote IP=0:0:0:0:0:0:0:1%0
Database connection closed for Application.
Hãy để ý thứ tự của các dòng log. Chúng được ghi theo đúng trình tự thực thi và dòng log cuối cùng sẽ xuất hiện khi bạn tắt ứng dụng hoặc tắt container.
Trên đây là toàn bộ nội dung về ServletContextListener trong các ứng dụng web Java. Bạn có thể tải code project ví dụ ở trên từ liên kết này và tự mình vọc vạch để hiểu sâu hơn. Trong bài tiếp theo, chúng ta sẽ khám phá cách sử dụng cookie và áp dụng trong các ví dụ servlet đơn giản khác.