Skip to content
CMO & CTO
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

  • Digital Experience
    • Experience Strategy
    • Experience-Driven Commerce
    • Multi-Channel Experience
    • Personalization & Targeting
    • SEO & Performance
    • User Journey & Behavior
  • Marketing Technologies
    • Analytics & Measurement
    • Content Management Systems
    • Customer Data Platforms
    • Digital Asset Management
    • Marketing Automation
    • MarTech Stack & Strategy
    • Technology Buying & ROI
  • Software Engineering
    • Software Engineering
    • Software Architecture
    • General Software
    • Development Practices
    • Productivity & Workflow
    • Code
    • Engineering Management
    • Business of Software
    • Code
    • Digital Transformation
    • Systems Thinking
    • Technical Implementation
  • About
CMO & CTO

Closing the Bridge Between Marketing and Technology, By Luis Fernandez

Filters and Listeners: Cross-Cutting the Right Way

Posted on November 6, 2010 By Luis Fernandez

Filters and Listeners: Cross Cutting the Right Way. Servlets from a practitioner view with lessons you can reuse.

The Problem We Keep Repeating

Every Java web app I see starts clean and ends with controllers doing everything. Authentication checks. Log noise. Timing. A bit of compression. Some cookie dance. It works, sure, but you pay for it with duplicated code and bugs that keep coming back. With Servlet 3.0 landing in the stacks we use today like Tomcat 7, GlassFish 3, and Jetty 7, we have a boring but powerful answer sitting right there: filters and listeners. They are the right place for cross cutting work that does not belong in your business code.

Think of filters as a gate that every request walks through and listeners as little ears that react to app start, stop, new request, new session, and similar life cycle events. Use them and your controllers can breathe again.

Three Cases You Can Ship This Week

Case 1. Login checks without touching controllers

Stop sprinkling isLoggedIn across ten servlets. Put it in one filter and be done. With Servlet 3.0 you can use annotations and skip web xml if you want.

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.*;

@WebFilter(urlPatterns = {"/app/*"})
public class AuthFilter implements Filter {

  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
      throws java.io.IOException, ServletException {
    HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) res;

    HttpSession session = request.getSession(false);
    boolean loggedIn = session != null && session.getAttribute("user") != null;
    boolean loginRequest = request.getRequestURI().endsWith("/login");

    if (loggedIn || loginRequest) {
      chain.doFilter(request, response);
    } else {
      response.sendRedirect(request.getContextPath() + "/login");
    }
  }
}

This puts access control in one place. Your controllers stop caring about who you are and can focus on what they do.

Case 2. Request id and logging that actually helps

When production gets noisy you want a way to tie a log line to a request. Create one id per request in a filter and stash it in MDC if you use SLF4J or Logback. Pair it with a request listener for timing.

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import org.slf4j.MDC;
import java.util.UUID;

@WebFilter("/*")
public class CorrelationFilter implements Filter {
  public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
      throws java.io.IOException, ServletException {
    String rid = UUID.randomUUID().toString();
    MDC.put("rid", rid);
    req.setAttribute("rid", rid);
    try {
      chain.doFilter(req, res);
    } finally {
      MDC.remove("rid");
    }
  }
}
import javax.servlet.*;
import javax.servlet.annotation.WebListener;

@WebListener
public class TimingListener implements ServletRequestListener {
  public void requestInitialized(ServletRequestEvent sre) {
    sre.getServletRequest().setAttribute("t0", System.nanoTime());
  }
  public void requestDestroyed(ServletRequestEvent sre) {
    Object t0 = sre.getServletRequest().getAttribute("t0");
    if (t0 != null) {
      long ms = (System.nanoTime() - (Long) t0) / 1_000_000;
      System.out.println("[perf] rid=" + sre.getServletRequest().getAttribute("rid") + " took " + ms + " ms");
    }
  }
}

Now every log line can include rid and you can see how long things take without touching your controllers.

Case 3. Startup bootstrapping and cleanup that never leaks

Creating a data source, warming caches, and closing stuff on shutdown all belong in a ServletContextListener. No more static singletons created on the first hit.

import javax.servlet.*;
import javax.servlet.annotation.WebListener;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSource;

@WebListener
public class AppBoot implements ServletContextListener {

  private BasicDataSource ds;

  public void contextInitialized(ServletContextEvent sce) {
    ds = new BasicDataSource();
    ds.setUrl("jdbc:mysql://localhost/app");
    ds.setUsername("app");
    ds.setPassword("secret");
    sce.getServletContext().setAttribute("ds", ds);
    System.out.println("App started. DataSource ready.");
  }

  public void contextDestroyed(ServletContextEvent sce) {
    try { ds.close(); } catch (Exception ignore) {}
    System.out.println("App stopped. DataSource closed.");
  }
}

Any servlet can now grab the data source from context and you know it will be closed when the container stops.

Objections and Replies

We already have this check in our controllers. Great, you can remove it from there and centralize. Future fixes happen once. Less risk. Fewer bugs.

We use Spring so we can just add an interceptor. Interceptors are fine inside Spring. Filters and listeners sit at the container door. They also cover static content, JSP, or any other framework you plug in later. You can mix both. Use the filter for the broad rule and the interceptor for framework level hooks.

Web xml is painful. With Servlet 3.0 you can use @WebFilter and @WebListener. If your container is still on older servlet spec, keep web xml but it is a one time edit and done. Either way your app code gets simpler.

Async or Comet will break this. Filters still wrap the request. For async, make sure you clean up MDC or ThreadLocal data in a finally block and use the async listeners if you need deeper hooks. The pattern holds.

Security frameworks already exist. True, and they are good. A small auth filter is still useful for simple apps or for rules that sit before a bigger framework, like blocking by IP or short circuiting bots. Filters are your quick move.

Do This Next

Pick one cross cutting concern and move it out of your controllers today. You will feel the difference right away.

  • Add a CorrelationFilter with a request id and put it in your log pattern. Search by that id during the next bug hunt.
  • Create an AuthFilter for your private routes. Remove the repeated checks from two controllers as a start.
  • Add an AppBoot context listener to set up shared resources and to close them when the server stops.
  • Turn one slow spot into a measured one with the TimingListener. Keep the data and decide what to speed up later.
  • Write a quick readme so the team knows where to add new cross cutting code. One page is enough.

We spend a lot of time building features. The boring glue decides if tomorrow is calm or on fire. Filters and listeners are not flashy but they pay back every week. If you are on Tomcat 7 or GlassFish 3 you already have everything you need. Keep your controllers clean. Let the container help you. That is the right way to handle cross cutting in Java web apps.

General Software Software Engineering

Post navigation

Previous post
Next post
  • Digital Experience (94)
    • Experience Strategy (19)
    • Experience-Driven Commerce (5)
    • Multi-Channel Experience (9)
    • Personalization & Targeting (21)
    • SEO & Performance (10)
  • Marketing Technologies (92)
    • Analytics & Measurement (14)
    • Content Management Systems (45)
    • Customer Data Platforms (4)
    • Digital Asset Management (8)
    • Marketing Automation (6)
    • MarTech Stack & Strategy (10)
    • Technology Buying & ROI (3)
  • Software Engineering (310)
    • Business of Software (20)
    • Code (30)
    • Development Practices (52)
    • Digital Transformation (21)
    • Engineering Management (25)
    • General Software (82)
    • Productivity & Workflow (30)
    • Software Architecture (85)
    • Technical Implementation (23)
  • 2025 (12)
  • 2024 (8)
  • 2023 (18)
  • 2022 (13)
  • 2021 (3)
  • 2020 (8)
  • 2019 (8)
  • 2018 (23)
  • 2017 (17)
  • 2016 (40)
  • 2015 (37)
  • 2014 (25)
  • 2013 (28)
  • 2012 (24)
  • 2011 (30)
  • 2010 (42)
  • 2009 (25)
  • 2008 (13)
  • 2007 (33)
  • 2006 (26)

Ab Testing Adobe Adobe Analytics Adobe Target AEM agile-methodologies Analytics architecture-patterns CDP CMS coding-practices content-marketing Content Supply Chain Conversion Optimization Core Web Vitals customer-education Customer Data Platform Customer Experience Customer Journey DAM Data Layer Data Unification documentation DXP Individualization java Martech metrics mobile-development Mobile First Multichannel Omnichannel Personalization product-strategy project-management Responsive Design Search Engine Optimization Segmentation seo spring Targeting Tracking user-experience User Journey web-development

©2025 CMO & CTO | WordPress Theme by SuperbThemes