Пример слушателя сервлета ServletContextListener

ServletContextListener – один из многих слушателей сервлетов, которые у нас есть. Это пятая статья в серии Веб-приложения на Java, вам может быть интересно также ознакомиться с предыдущими четырьмя статьями.

  1. Веб-приложения на Java
  2. Сервлеты в Java
  3. Управление сессиями в сервлетах
  4. Фильтр сервлетов

Слушатель сервлетов

В этом учебнике мы рассмотрим слушатель сервлетов, преимущества слушателей сервлетов, некоторые общие задачи, которые мы можем выполнять с помощью слушателей, интерфейсы слушателей сервлетов и объекты событий. В конце мы создадим простой веб-проект, чтобы показать пример распространенной реализации слушателя для ServletContext, Session и ServletRequest.

  1. Зачем нам нужен слушатель сервлетов?

  2. Интерфейсы слушателей сервлетов и объекты событий

  3. Настройка слушателя сервлетов

  4. Пример слушателя сервлетов

  5. ServletContextListener

  6. ServletContextAttributeListener

  7. HttpSessionListener

  8. ServletRequestListener

  9. Зачем у нас есть слушатель сервлетов?

Мы знаем, что с помощью ServletContext мы можем создавать атрибуты с областью применения приложения, к которым могут обращаться все другие сервлеты, но мы можем инициализировать параметры инициализации ServletContext только как String в файле развёртывания (web.xml). Что если наше приложение ориентировано на базу данных, и мы хотим установить атрибут в ServletContext для подключения к базе данных. Если ваше приложение имеет одну точку входа (вход пользователя), тогда вы можете сделать это в первом запросе сервлета, но если у нас есть несколько точек входа, то делать это везде приведет к избыточному коду. Кроме того, если база данных недоступна или настроена неправильно, мы не узнаем об этом до тех пор, пока не поступит первый запрос клиента на сервер. Чтобы обработать эти сценарии, сервлет API предоставляет интерфейсы слушателей, которые мы можем реализовать и настроить для прослушивания события и выполнения определенных операций. Событие – это возникновение чего-то, в мире веб-приложений событием может быть инициализация приложения, уничтожение приложения, запрос от клиента, создание/уничтожение сеанса, изменение атрибута в сеансе и т. д. Servlet API предоставляет различные типы интерфейсов слушателей, которые мы можем реализовать и настроить в web.xml для обработки чего-то при возникновении определенного события. Например, в вышеприведенном сценарии мы можем создать слушателя для события запуска приложения, чтобы прочитать параметры инициализации контекста и создать подключение к базе данных и установить его в атрибут контекста для использования другими ресурсами. ### Интерфейсы слушателей сервлетов и объекты событий

  1. javax.servlet.AsyncEvent – Событие, возникающее при завершении асинхронной операции, запущенной на ServletRequest (через вызов ServletRequest#startAsync или ServletRequest#startAsync(ServletRequest, ServletResponse)), завершившейся по тайм-ауту или вызвавшей ошибку.
  2. javax.servlet.http.HttpSessionBindingEvent – События этого типа либо отправляются объекту, реализующему HttpSessionBindingListener при его привязке или отвязке от сеанса, либо HttpSessionAttributeListener, настроенному в web.xml, когда любой атрибут привязывается, отвязывается или заменяется в сеансе. Сеанс привязывает объект вызовом HttpSession.setAttribute и отвязывает объект вызовом HttpSession.removeAttribute. Мы можем использовать это событие для завершения действий при удалении объекта из сеанса.
  3. javax.servlet.http.HttpSessionEvent – Это класс, представляющий события уведомлений об изменениях в сеансах веб-приложения.
  4. javax.servlet.ServletContextAttributeEvent – Класс событий для уведомлений об изменениях в атрибутах ServletContext веб-приложения.
  5. javax.servlet.ServletContextEvent – Это класс события для уведомлений о изменениях в контексте сервлета веб-приложения.
  6. javax.servlet.ServletRequestEvent – События этого типа указывают на события жизненного цикла для ServletRequest. Источником события является ServletContext этого веб-приложения.
  7. javax.servlet.ServletRequestAttributeEvent – Это класс события для уведомлений об изменениях в атрибутах запроса сервлета в приложении.

API сервлетов предоставляет следующие интерфейсы Listener.

  1. javax.servlet.AsyncListener – Слушатель, который будет уведомлен в случае завершения, истечения времени ожидания или возникновения ошибки асинхронной операции, запущенной на ServletRequest, к которому был добавлен слушатель.

  2. javax.servlet.ServletContextListener – Интерфейс для получения уведомлений о событиях жизненного цикла ServletContext.

  3. javax.servlet.ServletContextAttributeListener – Интерфейс для получения уведомлений о событиях изменения атрибутов ServletContext.

  4. javax.servlet.ServletRequestListener – Интерфейс для получения уведомлений о событиях запросов, поступающих и выходящих из области видимости веб-приложения.

  5. javax.servlet.ServletRequestAttributeListener – Интерфейс для получения уведомлений о событиях изменения атрибутов ServletRequest.

  6. javax.servlet.http.HttpSessionListener – Интерфейс для получения уведомлений о событиях изменения жизненного цикла HttpSession.

  7. javax.servlet.http.HttpSessionBindingListener – Позволяет объекту получать уведомления при привязке или отвязке от сеанса.

  8. javax.servlet.http.HttpSessionAttributeListener – Интерфейс для получения уведомлений о событиях изменения атрибутов HttpSession.

  9. javax.servlet.http.HttpSessionActivationListener – Объекты, привязанные к сеансу, могут прослушивать события контейнера, уведомляющие их о том, что сеансы будут пассивированы, и о том, что сеанс будет активирован. Контейнер, который мигрирует сеансы между виртуальными машинами или сохраняет сеансы, должен уведомлять все атрибуты, привязанные к сеансам, реализующие HttpSessionActivationListener.

  10. Настройка прослушивателя сервлета

Мы можем использовать аннотацию @WebListener для объявления класса как слушателя, однако класс должен реализовать один или несколько интерфейсов слушателей. Мы можем определить слушателя в web.xml следующим образом:

<listener>
    <listener-class>
    com.journaldev.listener.AppContextListener
    </listener-class>
</listener>
  1. Пример слушателя сервлета

Давайте создадим простое веб-приложение, чтобы увидеть слушатель сервлета в действии. Мы создадим динамический веб-проект в Eclipse ServletListenerExample, структура которого будет выглядеть как на изображении ниже. web.xml: В файле развёртывания я определю некоторые параметры инициализации контекста и конфигурацию слушателя.

<?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: Это класс для подключения к базе данных, в упрощенной форме я не предоставляю код для реального подключения к базе данных. Мы установим этот объект в качестве атрибута контекста сервлета.

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;
		//создаем соединение с базой данных сейчас
		
	}
	
	public Connection getConnection(){
		return this.con;
	}
	
	public void closeConnection(){
		//закрываем соединение с базой данных здесь
	}
}

MyServlet: Простой класс сервлета, где я буду работать с сессией, атрибутами и т. д.

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);
	}

}

Теперь мы реализуем классы слушателей, я предоставляю примеры классов слушателей для часто используемых слушателей – ServletContextListener, ServletContextAttributeListener, ServletRequestListener и HttpSessionListener.27. ## ServletContextListener

Мы будем считывать параметры инициализации контекста сервлета для создания объекта DBConnectionManager и установки его в качестве атрибута объекта 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");
    	
    	//создаем подключение к базе данных из параметров инициализации и устанавливаем его в контекст
    	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.");
    	
    }
	
}
  1. ServletContextAttributeListener

A simple implementation to log the event when attribute is added, removed or replaced in servlet context.

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()+"}");
    }
	
}
  1. HttpSessionListener

A simple implementation to log the event when session is created or destroyed.

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());
    }
	
}
  1. ServletRequestListener

A simple implementation of ServletRequestListener interface to log the ServletRequest IP address when request is initialized and destroyed.

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());
    }
	
}

Теперь, когда мы развернем наше приложение и обратимся к MyServlet в браузере по URL-адресу https://localhost:8080/ServletListenerExample/MyServlet, мы увидим следующие записи в файле журнала сервера.

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.

Обратите внимание на последовательность записей и то, что они выполняются в порядке. Последняя запись появится при завершении приложения или остановке контейнера.

Вот и все для слушателя в сервлете. Далее мы рассмотрим куки и несколько общих примеров сервлетов. Вы можете загрузить проект по ссылке ниже и поиграться с ним, чтобы узнать больше.

Пример проекта прослушивателя сервлета для скачивания

Посмотрите следующую статью в серии о Куки в сервлете.

Source:
https://www.digitalocean.com/community/tutorials/servletcontextlistener-servlet-listener-example