Tutorials Logic, IN info@tutorialslogic.com

Servlet Listeners ServletContextListener, HttpSessionListener

Container Events

Jakarta Servlet listeners receive lifecycle notifications from the container. Context listeners observe application startup and shutdown, session listeners observe session creation and destruction, and request listeners observe request boundaries. They are useful for initializing and releasing shared infrastructure or collecting lifecycle metrics, not for handling ordinary route logic.

After this lesson, you can select the listener interface that matches an event, keep callbacks thread-safe, avoid slow startup and shutdown work, and understand why some destruction events are not guaranteed after a process crash.

What are Servlet Listeners?

Servlet Listeners are event-driven components that respond to lifecycle events in the web application. They implement specific listener interfaces and are notified when events occur (application startup/shutdown, session creation/destruction, request creation/destruction).

Listener Interface Events Use Case
ServletContextListener contextInitialized, contextDestroyed App startup/shutdown tasks
ServletContextAttributeListener attributeAdded, attributeRemoved, attributeReplaced Monitor app-scope attributes
HttpSessionListener sessionCreated, sessionDestroyed Track active sessions
HttpSessionAttributeListener attributeAdded, attributeRemoved, attributeReplaced Monitor session attributes
ServletRequestListener requestInitialized, requestDestroyed Request logging, timing
HttpSessionBindingListener valueBound, valueUnbound Object notified when added to session

ServletContextListener - App Startup/Shutdown

ServletContextListener - App Startup/Shutdown
package com.example.listeners;

import jakarta.servlet.*;
import jakarta.servlet.annotation.WebListener;
import java.sql.*;

@WebListener
public class AppContextListener implements ServletContextListener {

    private Connection dbConnection;

    // Called when the web application starts
    @Override
    public void contextInitialized(ServletContextEvent event) {
        ServletContext context = event.getServletContext();
        System.out.println("Application starting...");

        // Initialize shared resources
        try {
            // Initialize DB connection pool
            Class.forName("com.mysql.cj.jdbc.Driver");
            dbConnection = DriverManager.getConnection(
                "jdbc:mysql://localhost:3306/mydb", "root", "password");

            // Store in application scope for all servlets to use
            context.setAttribute("dbConnection", dbConnection);
            context.setAttribute("appStartTime", System.currentTimeMillis());
            context.setAttribute("appVersion", "1.0.0");

            System.out.println("Database connection initialized");
        } catch (Exception e) {
            System.err.println("Failed to initialize DB: " + e.getMessage());
        }
    }

    // Called when the web application shuts down
    @Override
    public void contextDestroyed(ServletContextEvent event) {
        System.out.println("Application shutting down...");
        // Release resources
        try {
            if (dbConnection != null && !dbConnection.isClosed()) {
                dbConnection.close();
                System.out.println("Database connection closed");
            }
        } catch (SQLException e) {
            System.err.println("Error closing DB: " + e.getMessage());
        }
    }
}

HttpSessionListener and ServletRequestListener

Session and Request Listeners

Session and Request Listeners
@WebListener
public class SessionCountListener implements HttpSessionListener {

    // Thread-safe counter for active sessions
    private static java.util.concurrent.atomic.AtomicInteger activeSessions
            = new java.util.concurrent.atomic.AtomicInteger(0);

    @Override
    public void sessionCreated(HttpSessionEvent event) {
        int count = activeSessions.incrementAndGet();
        System.out.println("Session created: " + event.getSession().getId()
                + " | Active sessions: " + count);
        // Store count in application scope
        event.getSession().getServletContext()
             .setAttribute("activeSessions", count);
    }

    @Override
    public void sessionDestroyed(HttpSessionEvent event) {
        int count = activeSessions.decrementAndGet();
        System.out.println("Session destroyed: " + event.getSession().getId()
                + " | Active sessions: " + count);
        event.getSession().getServletContext()
             .setAttribute("activeSessions", count);
    }

    public static int getActiveSessions() {
        return activeSessions.get();
    }
}

HttpSessionListener and ServletRequestListener - Java Example

HttpSessionListener and ServletRequestListener - Java Example
@WebListener
public class RequestTimingListener implements ServletRequestListener {

    @Override
    public void requestInitialized(ServletRequestEvent event) {
        // Store start time in request attribute
        event.getServletRequest().setAttribute("startTime", System.currentTimeMillis());
    }

    @Override
    public void requestDestroyed(ServletRequestEvent event) {
        Long startTime = (Long) event.getServletRequest().getAttribute("startTime");
        if (startTime != null) {
            long duration = System.currentTimeMillis() - startTime;
            HttpServletRequest req = (HttpServletRequest) event.getServletRequest();
            System.out.println("Request to " + req.getRequestURI()
                    + " took " + duration + "ms");
        }
    }
}

Context Lifecycle

ServletContextListener.contextInitialized runs after the web application context is ready and before the application begins normal service. Initialize bounded shared resources here only when the container or dependency-injection framework does not already manage them. Publish a successfully created resource through the ServletContext so consumers have one explicit owner.

contextDestroyed is the matching place to close executors, clients, or pools owned by the listener. Make cleanup idempotent and null-safe because partial startup can leave only some resources initialized. A forced process termination may skip graceful callbacks, so durable correctness must not depend on shutdown code running.

Request and Session Events

Request listeners are suitable for lightweight measurement or context setup that truly follows the entire servlet request. Filters are usually better when behavior must wrap the chain, alter headers, or stop processing. Session listeners can count active sessions, but a session is not the same as an active human and expiration timing depends on container policy.

Attribute listeners report additions, removals, and replacements. Avoid recursive updates: changing the same attribute from its listener can trigger another event. Treat event payloads as concurrent application data and do not assume callbacks for different requests arrive serially.

Operational Safety

Listener callbacks run on container-managed threads. Do not block them with unbounded network calls. Apply timeouts to essential startup checks and fail clearly when the application cannot operate. For nonessential warm-up or telemetry, hand work to a managed executor and define what happens during redeployment.

During local development, redeployment can initialize the application repeatedly. A listener that starts threads or registers static callbacks without releasing them can retain the old classloader and cause memory leaks. Verify that every resource it owns has a matching close path.

Before you move on

Lifecycle Review

4 checks
  • Choose context, request, session, or attribute events intentionally.
  • Keep callbacks thread-safe and bounded.
  • Close every shared resource the listener creates.
  • Do not rely on destruction callbacks for durable data.

Lifecycle Hazards

  • Starting an unmanaged thread at deployment.

    Use container-managed execution where available and stop owned work during shutdown.
  • Performing slow optional network calls during startup.

    Use strict timeouts or warm the resource asynchronously.
  • Counting sessions as exact online-user analytics.

    Treat the count as a session metric with expiration and multi-device limits.

Try this next

Own One Resource

0 of 2 completed

Next Step
Next Practice

Finish the concept here, then reinforce it with hands-on coding, interview prep, or a tool that matches the topic.

Browse Free Tutorials

Explore 500+ free tutorials across 20+ languages and frameworks.