Fading Coder

One Final Commit for the Last Sprint

Home > Tech > Content

Integrating Custom Servlets, Filters, and Listeners in Spring MVC

Tech May 14 1

Custom Servlet Implementation

package com.example.web.component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CustomHttpServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        System.out.println("CustomServlet Invoked");
        resp.getWriter().write("Response from Custom Servlet: " + req.getContextPath());
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doGet(req, resp);
    }
}

Custom Filter Implementation

package com.example.web.filter;

import javax.servlet.*;
import java.io.IOException;

public class LoggingFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
            throws IOException, ServletException {
        System.out.println("LoggingFilter: Request intercepted");
        chain.doFilter(request, response);
    }
}

Static Resource Filter

package com.example.web.filter;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.OutputStream;

public class AssetDeliveryFilter implements Filter {
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) 
            throws IOException, ServletException {
        HttpServletRequest httpReq = (HttpServletRequest) request;
        String uri = httpReq.getServletPath();
        String diskPath = httpReq.getServletContext().getRealPath(uri);
        
        try (OutputStream out = response.getOutputStream(); 
             FileInputStream fis = new FileInputStream(diskPath)) {
            byte[] buffer = new byte[1024];
            int bytesRead;
            while ((bytesRead = fis.read(buffer)) != -1) {
                out.write(buffer, 0, bytesRead);
            }
            out.flush();
        }
    }
}

Custom Listener Implementation

package com.example.web.listener;

import javax.servlet.ServletRequestEvent;
import javax.servlet.ServletRequestListener;

public class RequestAuditListener implements ServletRequestListener {
    @Override
    public void requestInitialized(ServletRequestEvent sre) {
        System.out.println("Request Initialized");
    }

    @Override
    public void requestDestroyed(ServletRequestEvent sre) {
        System.out.println("Request Destroyed");
    }
}

Method 1: Using WebApplicationInitializer (Servlet 3.0+)

To register these components programmatically, implement the WebApplicationInitializer interface. Spring detects this via the Servlet 3.0 ServletContainerInitializer mechanism.

package com.example.web.setup;

import com.example.web.component.CustomHttpServlet;
import com.example.web.filter.AssetDeliveryFilter;
import com.example.web.filter.LoggingFilter;
import com.example.web.listener.RequestAuditListener;
import org.springframework.web.WebApplicationInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;

public class AppInitializer implements WebApplicationInitializer {
    @Override
    public void onStartup(ServletContext context) throws ServletException {
        // Register Servlet
        context.addServlet("customServlet", CustomHttpServlet.class)
               .addMapping("/custom");

        // Register Filters
        context.addFilter("loggingFilter", LoggingFilter.class)
               .addMappingForUrlPatterns(null, false, "/*");
               
        context.addFilter("assetFilter", AssetDeliveryFilter.class)
               .addMappingForUrlPatterns(null, false, "/assets/*");

        // Register Listeners
        context.addListener(RequestAuditListener.class);
    }
}

Registration API Overloads

The ServletContext provides several overloads for adding components:

  • Servlets: addServlet(String name, String className | Servlet instance | Class<?>)
  • Filters: addFilter(String name, String className | Filter instance | Class<?>)
  • Listeners: addListener(String className | Listener instance | Class<?>)

Filter Execution Order

When using addMappingForUrlPatterns(EnumSet<DispatcherType>, boolean isMatchAfter, String...), the execution order is determined by the registration sequence in the onStartup method. Filters registered with isMatchAfter = false take precedence over those set to true.

Mechanism Behind the Magic

In a Servlet 3.0+ container, the server scans for implementations of ServletContainerInitializer. Spring provides SpringServletContainerInitializer, which specifically looks for classes annotated with @HandlesTypes(WebApplicationInitializer.class). It then instantiates and runs the onStartup method of all discovered implementations.

// Simplified logic from SpringServletContainerInitializer
public void onStartup(Set<Class<?>> webAppInitializerClasses, ServletContext servletContext) {
    List<WebApplicationInitializer> initializers = new ArrayList<>();
    
    for (Class<?> clazz : webAppInitializerClasses) {
        // Ensure it's a concrete class implementing the interface
        if (!clazz.isInterface() && WebApplicationInitializer.class.isAssignableFrom(clazz)) {
            initializers.add((WebApplicationInitializer) clazz.newInstance());
        }
    }

    // Sort and execute
    AnnotationAwareOrderComparator.sort(initializers);
    for (WebApplicationInitializer initializer : initializers) {
        initializer.onStartup(servletContext); // Your custom logic runs here
    }
}

Related Articles

Understanding Strong and Weak References in Java

Strong References Strong reference are the most prevalent type of object referencing in Java. When an object has a strong reference pointing to it, the garbage collector will not reclaim its memory. F...

Comprehensive Guide to SSTI Explained with Payload Bypass Techniques

Introduction Server-Side Template Injection (SSTI) is a vulnerability in web applications where user input is improper handled within the template engine and executed on the server. This exploit can r...

Implement Image Upload Functionality for Django Integrated TinyMCE Editor

Django’s Admin panel is highly user-friendly, and pairing it with TinyMCE, an effective rich text editor, simplifies content management significantly. Combining the two is particular useful for bloggi...

Leave a Comment

Anonymous

◎Feel free to join the discussion and share your thoughts.