Servlet Context Listener Beispiel
In diesem Tutorial werden wir den Servlet Listener untersuchen, die Vorteile von Servlet Listeners erörtern, einige gängige Aufgaben, die wir mit Listeners durchführen können, Servlet API Listener-Schnittstellen und Event-Objekte. Am Ende werden wir ein einfaches Webprojekt erstellen, um ein Beispiel für die häufig verwendete Listener-Implementierung für ServletContextListener, Session und ServletRequest zu zeigen.
Wir wissen, dass wir mit ServletContextListener ein Attribut mit Anwendungsbereich erstellen können, auf das alle anderen Servlets zugreifen können, aber wir können ServletContext-Init-Parameter nur als String im Deployment-Descriptor (web.xml) initialisieren. Was ist, wenn unsere Anwendung datenbankorientiert ist und wir ein Attribut in ServletContext für die Datenbankverbindung setzen wollen. Wenn Ihre Anwendung einen einzelnen Einstiegspunkt (Benutzeranmeldung) hat, können Sie dies beim ersten Servlet-Request tun, aber wenn wir mehrere Einstiegspunkte haben, führt dies überall zu einer Menge Code-Redundanz. Auch wenn die Datenbank nicht verfügbar oder nicht richtig konfiguriert ist, werden wir es nicht wissen, bis die erste Client-Anfrage an den Server kommt. Um diese Szenarien zu bewältigen, bietet die Servlet-API Listener-Schnittstellen an, die wir implementieren und konfigurieren können, um auf ein Ereignis zu hören und bestimmte Operationen durchzuführen.
Die Servlet-API bietet verschiedene Arten von Listeners für verschiedene Arten von Events an. Listener-Schnittstellen deklarieren Methoden, um mit einer Gruppe ähnlicher Ereignisse zu arbeiten, zum Beispiel haben wir den ServletContextListener, um auf das Start- und Shutdown-Ereignis des Kontexts zu hören. Jede Methode in der Listener-Schnittstelle nimmt ein Event-Objekt als Eingabe. Das Event-Objekt funktioniert als Wrapper, um den Listeners ein spezifisches Objekt zur Verfügung zu stellen. Die Servlet-API bietet folgende Event-Objekte an.
- javax.servlet.AsyncEvent – Ein Ereignis, das ausgelöst wird, wenn die asynchrone Operation, die auf einem ServletRequest initiiert wurde (über einen Aufruf von ServletRequest#startAsync oder ServletRequest#startAsync(ServletRequest, ServletResponse)), abgeschlossen, abgelaufen oder einen Fehler verursacht hat.
- javax.servlet.http.HttpSessionBindingEvent – Ereignisse dieses Typs werden entweder an ein Objekt gesendet, das HttpSessionBindingListener implementiert, wenn es an eine Session gebunden oder von dieser gelöst wird, oder an einen HttpSessionAttributeListener, der in der web.xml konfiguriert wurde, wenn ein Attribut in einer Session gebunden, gelöst oder ersetzt wird. Die Session bindet das Objekt durch einen Aufruf von HttpSession.setAttribute und löst das Objekt durch einen Aufruf von HttpSession.removeAttribute. Dieses Ereignis kann für Aufräumarbeiten verwendet werden, wenn ein Objekt aus der Session entfernt wird.
- javax.servlet.http.HttpSessionEvent – Dies ist die Klasse, die Ereignisbenachrichtigungen für Änderungen an Sessions innerhalb einer Webanwendung darstellt.
- javax.servlet.ServletContextAttributeEvent – Ereignisklasse für Benachrichtigungen über Änderungen an den Attributen des ServletContext einer Webanwendung.
- javax.servlet.ServletContextEvent – Dies ist die Ereignisklasse für Benachrichtigungen über Änderungen am Servlet-Kontext einer Webanwendung.
- javax.servlet.ServletRequestEvent – Ereignisse dieser Art zeigen Lebenszyklusereignisse für ein ServletRequest an. Die Quelle des Ereignisses ist der ServletContext dieser Webanwendung.
- javax.servlet.ServletRequestAttributeEvent – Dies ist die Ereignisklasse für Benachrichtigungen über Änderungen an den Attributen der Servlet-Anfrage in einer Anwendung.
Die Servlet-API bietet folgende Listener-Schnittstellen an.
-
- javax.servlet.AsyncListener – Ein Listener, der benachrichtigt wird, wenn eine asynchrone Operation, die auf einem ServletRequest initiiert wurde, zu dem der Listener hinzugefügt wurde, abgeschlossen, abgelaufen oder einen Fehler verursacht hat.
- javax.servlet.ServletContextListener – Schnittstelle für den Empfang von Benachrichtigungsereignissen über Lebenszyklusänderungen des ServletContext.
- javax.servlet.ServletContextAttributeListener – Schnittstelle für den Empfang von Benachrichtigungsereignissen über Änderungen an ServletContext-Attributen.
- javax.servlet.ServletRequestListener – Schnittstelle für den Empfang von Benachrichtigungsereignissen über Anfragen, die in den Geltungsbereich einer Webanwendung eintreten und diesen verlassen.
- javax.servlet.ServletRequestAttributeListener – Schnittstelle für den Empfang von Benachrichtigungsereignissen über ServletRequest-Attributänderungen.
- javax.servlet.http.HttpSessionListener – Schnittstelle für den Empfang von Benachrichtigungsereignissen über Lebenszyklusänderungen der HttpSession.
- javax.servlet.http.HttpSessionBindingListener – Veranlasst ein Objekt, benachrichtigt zu werden, wenn es an eine Session gebunden oder von dieser gelöst wird.
- javax.servlet.http.HttpSessionAttributeListener – Schnittstelle für den Empfang von Benachrichtigungsereignissen über Änderungen an HttpSession-Attributen.
- javax.servlet.http.HttpSessionActivationListener – Objekte, die an eine Session gebunden sind, können Benachrichtigungen von Container-Ereignissen empfangen, die sie darüber informieren, dass Sessions passiviert werden und dass die Session aktiviert wird. Ein Container, der Sessions zwischen VMs migriert oder Sessions speichert, muss alle Attribute, die an Sessions gebunden sind und HttpSessionActivationListener implementieren, benachrichtigen.
Wir können die Annotation @WebListener verwenden, um eine Klasse als Listener zu deklarieren, allerdings sollte die Klasse eine oder mehrere der Listener-Schnittstellen implementieren. Wir können einen Listener in web.xml wie folgt definieren:
<listener>
<listener-class>
com.journaldev.listener.AppContextListener
</listener-class>
</listener>
Servlet Listener Beispiel
Lassen Sie uns eine einfache Webanwendung erstellen, um den Servlet Listener in Aktion zu sehen. Wir werden ein dynamisches Webprojekt in Eclipse mit dem Namen ServletListenerExample erstellen, dessen Projektstruktur wie im untenstehenden Bild aussehen wird.
web.xml: Im Deployment-Descriptor werde ich einige Kontext-Initialisierungsparameter und Listener-Konfigurationen definieren.
<?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: Dies ist die Klasse für die Datenbankverbindung. Der Einfachheit halber gebe ich keinen Code für die tatsächliche Datenbankverbindung an. Wir werden dieses Objekt als Attribut zum Servlet-Kontext setzen.
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: Eine einfache Servlet-Klasse, in der ich mit Sitzungen, Attributen usw. arbeiten werde.
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);
}
}
Nun werden wir Listener-Klassen implementieren. Ich stelle Beispiel-Listener-Klassen für häufig verwendete Listener zur Verfügung – ServletContextListener, ServletContextAttributeListener, ServletRequestListener und HttpSessionListener.
Wir werden die Init-Parameter des Servlet-Kontexts lesen, um das DBConnectionManager-Objekt zu erstellen und es als Attribut zum ServletContext-Objekt zu setzen.
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.");
}
}
Servlet Context Attribute Listener
Eine einfache Implementierung, um das Ereignis zu protokollieren, wenn ein Attribut im Servlet-Kontext hinzugefügt, entfernt oder ersetzt wird.
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()+"}");
}
}
Servle tContext Listener – Http Session Listener
Eine einfache Implementierung, um das Ereignis zu protokollieren, wenn eine Sitzung erstellt oder zerstört wird.
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());
}
}
Servlet Context Listener – Servlet Request Listener
Eine einfache Implementierung der ServletRequestListener-Schnittstelle, um die IP-Adresse der ServletRequest zu protokollieren, wenn eine Anfrage initialisiert und zerstört wird.
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());
}
}
Wenn wir nun unsere Anwendung bereitstellen und MyServlet im Browser mit der URL https://localhost:8080/ServletListenerExample/MyServlet aufrufen, werden wir folgende Protokolle in der Server-Logdatei sehen.
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.
Beachten Sie die Reihenfolge der Protokolle und deren Ausführungsreihenfolge. Das letzte Protokoll erscheint, wenn Sie die Anwendung herunterfahren oder den Container beenden.