Interview Java ‐ J2EE - Yash-777/MyWorld GitHub Wiki

Servlets

Servlet Container → Spring Container

Servlet Container
package javax.servlet;
Spring Container
package org.springframework.web.servlet;
/* A servlet is a small Java program that runs within a Web server. Servlets
 * receive and respond to requests from Web clients, usually across HTTP, the
 * HyperText Transfer Protocol.
 *
 * This interface defines methods to initialize a servlet, to service requests,
 * and to remove a servlet from the server. These are known as life-cycle */
public interface Servlet {

    /* Called by the servlet container to indicate to a servlet that the servlet
     * is being placed into service. */
    public void init(ServletConfig config) throws ServletException;
    public ServletConfig getServletConfig();

    /* Called by the servlet container to allow the servlet to respond to a request. */
    public void service(ServletRequest req, ServletResponse res)
            throws ServletException, IOException;
         
    public String getServletInfo();
    public void destroy();
}
/**
 * A servlet configuration object used by a servlet container to pass
 * information to a servlet during initialization.
 */
public interface ServletConfig {
    public String getServletName();
    public ServletContext getServletContext();
    public String getInitParameter(String name);
    public Enumeration getInitParameterNames();
}

public abstract class GenericServlet implements Servlet, ServletConfig,
        java.io.Serializable { }
      
package javax.servlet.http;
public abstract class HttpServlet extends GenericServlet {
   // Called by the server (via the service method) toallow a servlet to handle a GET request. 
   protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
      throws ServletException, IOException {
        String msg = lStrings.getString("http.method_get_not_supported");
        sendMethodNotAllowed(req, resp, msg);
    }
   //...
}
      
@SuppressWarnings("serial")
public abstract class HttpServletBean 
   extends HttpServlet implements EnvironmentCapable, EnvironmentAware {

   /** Logger available to subclasses. */
   protected final Log logger = LogFactory.getLog(getClass());
}

@SuppressWarnings("serial")
public abstract class FrameworkServlet 
   extends HttpServletBean implements ApplicationContextAware { }

@SuppressWarnings("serial")
public class DispatcherServlet extends FrameworkServlet { }
      

Java Filters

Filters are part of the Servlet container. They intercept the request before it reaches the Controller and the response before it goes back to the client.

Request Flow: Servlet Container → Spring Container Filter Chainpackage org.springframework.web.servlet;
HTTP Request: GET /api/test
         │
         ▼
┌─────────────────────── SERVLET CONTAINER ─────────────────────────────────────────┐
|    ┌────────────────────────────────────┐                                         |
|    │   Servlet Container (Tomcat)       │                                         |
|    └────────────────────────────────────┘                                         |
|         ↓                                                                         |
|    ┌────────────────────────────────────┐                                         |
|    │   Filter Chain Starts              │                                         |
|    └────────────────────────────────────┘                                         |
|         ↓                                                                         |
|    ┌────────────────────────────────────┐                                         |
|    │   CorsFilter.doFilter()            │  ← Can modify request/response          |
|    │   - Set CORS headers               │  ← Can block request                    |
|    │   - chain.doFilter()               │  ← Can log                              |
|    └────────────────────────────────────┘                                         |
|         ↓                                                                         |
|    ┌────────────────────────────────────┐ ┌────────────────────────────────────┐  |
|    │   AuthenticationFilter.doFilter()  │ │   LoggingFilter.doFilter()         │  |
|    │   - Validate JWT token             │ │   - Log request details            │  |
|    │   - Set SecurityContext            │ │   - chain.doFilter()               │  |
|    │   - chain.doFilter()               │ └────────────────────────────────────┘  |
|    └────────────────────────────────────┘                                         |
|         ↓                                                                         |
|    ╔════════════════════════════════════╗                                         |
|    ║   DispatcherServlet                ║  ← ENTRY TO SPRING MVC                  |
|    ║   (Spring's Front Controller)      ║                                         |
|    ╚════════════════════════════════════╝                                         |
└───────────────────────────────────────────────────────────────────────────────────┘
                               ↓
┌─────────────────────── SPRING CONTAINER ──────────────────────────────────────────┐
|    ┌────────────────────────────────────┐                                         |
|    │   Handler Mapping                  │                                         |
|    │   - Find @Controller method        │                                         |
|    └────────────────────────────────────┘                                         |
|         ↓                                                                         |
|    ┌────────────────────────────────────┐                                         |
|    │   Interceptor.preHandle()          │  ← Spring-level interception            |
|    └────────────────────────────────────┘                                         |
|         ↓                                                                         |
|    ┌────────────────────────────────────┐                                         |
|    │   @RestController Method           │                                         |
|    │   public String test() {...}       │                                         |
|    └────────────────────────────────────┘                                         |
|         ↓                                                                         |
|    ┌────────────────────────────────────┐                                         |
|    │   Interceptor.postHandle()         │                                         |
|    └────────────────────────────────────┘                                         |
|         ↓                                                                         |
|    ┌────────────────────────────────────┐                                         |
|    │   Response Rendering               │                                         |
|    └────────────────────────────────────┘                                         |
└───────────────────────────────────────────────────────────────────────────────────┘
         ↓
    ╔════════════════════════════════════╗
    ║   Back through Filter Chain        ║
    ║   (in reverse order)               ║
    ╚════════════════════════════════════╝
         │
         ▼
    HTTP Response to Client
   
package javax.servlet;
 /** A filter is an object that performs filtering tasks on either the request to a resource (a servlet or static
 * content), or on the response from a resource, or both.
 * 
 * Filters perform filtering in the doFilter method. Every Filter has access to a FilterConfig object from
 * which it can obtain its initialization parameters, a reference to the ServletContext which it can use, for example,
 * to load resources needed for filtering tasks.
 *
 * Examples that have been identified for this design are
 * 1) Authentication Filters 
 * 2) Logging and Auditing Filters 
 * 3) Image conversion Filters 
 * 4) Data compression Filters 
 * 5) Encryption Filters 
 * 6) Tokenizing Filters 
 * 7) Filters that trigger resource access events 
 * 8) XSL/T filters 
 * 9) Mime-type chain Filter
 * 
 * @since Servlet 2.3  */
public interface Filter {
   // Called once when filter is initialized
   default void init(FilterConfig filterConfig) throws ServletException {
   }

   // Called for every request
   void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
         throws IOException, ServletException;

   // Called once when filter is destroyed
   default void destroy() {
   }
}

/** A filter configuration object used by a servlet container to pass information to a filter during initialization.
 * @since Servlet 2.3 */
public interface FilterConfig {
    String getFilterName();
    ServletContext getServletContext();
    String getInitParameter(String name);
    Enumeration getInitParameterNames();
}

package org.springframework.web.filter;
public abstract class GenericFilterBean implements Filter, BeanNameAware, EnvironmentAware,
      EnvironmentCapable, ServletContextAware, InitializingBean, DisposableBean {

}
public abstract class OncePerRequestFilter extends GenericFilterBean {
   @Override
   public final void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
         throws ServletException, IOException {

      if (!(request instanceof HttpServletRequest) || !(response instanceof HttpServletResponse)) {
         throw new ServletException("OncePerRequestFilter just supports HTTP requests");
      }
      HttpServletRequest httpRequest = (HttpServletRequest) request;
      HttpServletResponse httpResponse = (HttpServletResponse) response;

      //...
   }
   // ...
}

Filter (Interface) - @since Servlet 2.3
FilterConfig (Interface): FilterRegistrationBean (RECOMMENDED) - @since Servlet 2.3
@interface WebFilter - @since Servlet 3.0 [WARNING: @Autowired may not work reliably!]
OncePerRequestFilter (Abstract Class)
Filter (Interface): The base Servlet API interface that all filters must implement.
Pros: Cons:
  • ✅ Automatic Spring bean registration
  • ✅ Dependency injection works
  • ✅ No need for @ServletComponentScan
  • ❌ Applies to ALL URLs (/*) by default
  • ❌ Less control over URL patterns
  • ❌ No init parameters support
// Regular Filter - may execute MULTIPLE times
// With request forwarding:
// GET /api/user → forwards to /api/user/details
// Output: "Executed" (twice!)
@Component
public class RegularFilter implements Filter {

    @Autowired
    private SomeService service;  // Can inject Spring beans

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        System.out.println("Filter initialized");
        // Read init parameters, initialize resources
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
		System.out.println("Executed"); // May print multiple times!

        // Pre-processing
        chain.doFilter(request, response); // Continue chain
        // Post-processing
    }

    @Override
    public void destroy() {
        System.out.println("Filter destroyed");
        // Cleanup resources
    }
}
      

FilterConfig (Interface): Configuration object passed to the filter during initialization. Provides access to: Filter name, Initialization parameters, ServletContext
Pros: Cons:
  • ✅ Full Spring integration
  • ✅ Complete control (URL patterns, order, init params)
  • ✅ Dependency injection works perfectly
  • ✅ Programmatic configuration
  • ✅ Can register multiple URL patterns easily
  • ❌ More verbose
  • ❌ Requires configuration class

Registering with Init Parameters:
@Configuration
public class FilterConfiguration {
    @Bean
    public FilterRegistrationBean filterToRegister() {
        FilterRegistrationBean registrationBean = 
            new FilterRegistrationBean<>();

        registrationBean.setFilter(new RegularFilter());
        registrationBean.addUrlPatterns("/*");

        // Set init parameters (accessible via FilterConfig)
        registrationBean.addInitParameter("allowedOrigins", "http://localhost:3000,http://example.com");
        registrationBean.addInitParameter("maxRequestSize", "2097152");

        return registrationBean;
    }
}
	  

@WebFilter + @ServletComponentScan
Pros: Cons:
  • ✅ Fine-grained URL pattern control
  • ✅ Init parameters support
  • ✅ Standard Servlet 3.0+ approach
  • ❌ Requires @ServletComponentScan
  • ❌ Dependency injection may not work
  • ❌ Not fully integrated with Spring lifecycle
  • ❌ Can't control order easily
// Enable scanning
@SpringBootApplication
@ServletComponentScan(basePackages = "com.example.filters")
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}
// Filter
@WebFilter(urlPatterns = "/api/*")
public class WebFilterExample implements Filter {

    // WARNING: @Autowired may not work reliably!
    // @Autowired private SomeService service;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, 
                         FilterChain chain) throws IOException, ServletException {
        System.out.println("@WebFilter executing");
        chain.doFilter(request, response);
    }
}
Spring Framework class that guarantees filter execution only once per request, even with forwards and includes.
    Guaranteed only single execution even on redirection of request.
  • Request Logging Filter
  • JWT Authentication Filter
  • InboundIntegratonLog: Request/Response Body Caching Filter
@Component
public class LoggingFilter extends OncePerRequestFilter {
 
    @Autowired
    private UserService userService;  // Dependency injection works!

    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                   HttpServletResponse response, 
                                   FilterChain filterChain) 
            throws ServletException, IOException {

        System.out.println("Executed ONLY ONCE"); // Guaranteed single execution

        // Pre-processing
        long startTime = System.currentTimeMillis();

        filterChain.doFilter(request, response);

        // Post-processing
        long duration = System.currentTimeMillis() - startTime;
        System.out.println("Request completed in " + duration + "ms");
    }
}
CachingRequestFilter extends OncePerRequestFilter
@Component
public class CachingRequestFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, 
                                   HttpServletResponse response, 
                                   FilterChain filterChain) 
            throws ServletException, IOException {

        // Wrap request to cache body (for multiple reads)
        CachedBodyHttpServletRequest cachedRequest = 
            new CachedBodyHttpServletRequest(request);

        // Wrap response to capture output
        ContentCachingResponseWrapper cachedResponse = 
            new ContentCachingResponseWrapper(response);

        try {
            filterChain.doFilter(cachedRequest, cachedResponse);
        } finally {
            // Log request body
            String requestBody = new String(cachedRequest.getCachedBody(), 
                            StandardCharsets.UTF_8);
            logger.debug("Request Body: {}", requestBody);

            // Log response body
            byte[] responseContent = cachedResponse.getContentAsByteArray();
            String responseBody = new String(responseContent, StandardCharsets.UTF_8);
            logger.debug("Response Body: {}", responseBody);
   
            // Important: Copy content back to response
            cachedResponse.copyBodyToResponse();
        }
    }
}
// Custom wrapper to cache request body
class CachedBodyHttpServletRequest extends HttpServletRequestWrapper {
    private byte[] cachedBody;

    public CachedBodyHttpServletRequest(HttpServletRequest request) 
            throws IOException {
        super(request);
        InputStream requestInputStream = request.getInputStream();
        this.cachedBody = StreamUtils.copyToByteArray(requestInputStream);
    }
    @Override
    public ServletInputStream getInputStream() {
        return new CachedBodyServletInputStream(this.cachedBody);
    }
    @Override
    public BufferedReader getReader() {
        ByteArrayInputStream byteArrayInputStream = 
            new ByteArrayInputStream(this.cachedBody);
        return new BufferedReader(
            new InputStreamReader(byteArrayInputStream));
    }
    public byte[] getCachedBody() {
        return cachedBody;
    }
}

⚠️ **GitHub.com Fallback** ⚠️