Servlet Filters
Filters are a core component of the Java Servlet specification, operating within the servlet container to pre-process requests and post-process responses. They execute before a request reaches a servlet and after the servlet generates a response, enabling tasks like logging, authentication, and data transformation.
Core Conecpts
- Lifecycle Management: The servlet container manages filter instances through
init(),doFilter(), anddestroy()methods. - Filter Chain: Multiple filters can be chained sequentially. The container invokes each filter's
doFilter()method, passing control viaFilterChain.doFilter()to proceed to the next filter or target servlet. - Request/Response Modification: Filters can wrap or alter
ServletRequestandServletResponseobjects but typically do not generate responses directly.
Implementation Example
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(urlPatterns = "/api/*")
public class AuthFilter implements Filter {
@Override
public void init(FilterConfig config) throws ServletException {
// Initialization logic
}
@Override
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
throws IOException, ServletException {
System.out.println("Authentication check");
// Custom logic (e.g., validate session)
chain.doFilter(req, resp);
System.out.println("Post-processing response");
}
@Override
public void destroy() {
// Cleanup resources
}
}
Common Use Cases
- Access control and authorization
- Logging request/response details
- Modifying request headers or encoding
- Response compression or caching
Key Considerations
- Order of execution in filter chains
- Proper resource cleanup in
destroy() - Exception handling to avoid breaking the request flow
Spring MVC Interceptors
Interceptors are specific to Spring MVC, providing fine-grained control over request processing within the DispatcherServlet flow. They intercept requests before and after controller execution, leveraging Spring's context for advanced functionality.
Core Concepts
- Integration with DispatcherServlet: Interceptors hook into Spring MVC's request handling pipeline, operating between DispatcherServlet and controller methods.
- Handler Mapping: Spring resolves the appropriate controller via handler mapping before interceptor execution.
- Interceptor Chain: Multiple interceptors execute in configured order, with methods
preHandle(),postHandle(), andafterCompletion(). - Method-Level Control: Interceptors can target specific controller methods, accessing handler metadata and model data.
Implementation Example
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class TimingInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
req.setAttribute("startTime", System.currentTimeMillis());
return true; // Continue processing
}
@Override
public void postHandle(HttpServletRequest req, HttpServletResponse res, Object handler, ModelAndView mv) {
Long start = (Long) req.getAttribute("startTime");
System.out.println("Request duration: " + (System.currentTimeMillis() - start) + "ms");
}
@Override
public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex) {
// Cleanup or final logging
}
}
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class MvcConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new TimingInterceptor()).addPathPatterns("/**");
}
}
Common Use Cases
- Method-level security checks
- Performance monitoring and metrics
- Transaction management
- Content negotiation and locale resolution
Key Considerations
preHandle()return value controls continuation (true/false)- Exception handling within interceptor methods
- Ordering in interceptor chains
Comparison of Filters and Interceptors
Similarities
- Both enable pre-processing and post-processing of HTTP requests/responses
- Support logging, security, and data manipulation
- Configurable via annotations or XML
Differences
- Framework/Standard: Filters are part of the Servlet specification; interceptors are Spring MVC components.
- Execution Layer: Filters operate at the servlet container level; interceptors work within Spring's DispatcherServlet flow.
- Granularity: Filters apply broadly to URL patterns; interceptors can target specific controller methods.
- Context Access: Filters use Servlet API only; interceptors can access Spring context, handler metadata, and model data.
- Exception Handling: Filters require manual exception handling; interceptors integrate with Spring's exception resolution.
Selection Guidelines
- Use filters for container-level processing independent of Spring (e.g., compression, encoding).
- Use interceptors for Spring-aware processing rqeuiring method-level control or Spring context data.
Logging Implementation Examples
Database Schema
CREATE TABLE operation_log (
id INT UNSIGNED PRIMARY KEY AUTO_INCREMENT,
class_name VARCHAR(100),
method_name VARCHAR(100),
method_description VARCHAR(200),
parameters TEXT,
return_value TEXT,
operator_id INT UNSIGNED,
operation_time DATETIME,
duration_ms BIGINT
);
Custom Annotation
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface OperationLog {
String description() default "";
}
AOP-Based Logging
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
@Aspect
@Component
public class LoggingAspect {
@Autowired
private HttpServletRequest currentRequest;
@Pointcut("@annotation(OperationLog)")
public void loggedOperations() {}
@Around("loggedOperations()")
public Object logOperation(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result;
try {
result = joinPoint.proceed();
long duration = System.currentTimeMillis() - start;
// Persist log with duration and result
} catch (Exception e) {
// Log exception details
throw e;
}
return result;
}
}
Interceptor-Based Logging
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@Component
public class AuditInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest req, HttpServletResponse res, Object handler) {
if (handler instanceof HandlerMethod) {
HandlerMethod method = (HandlerMethod) handler;
if (method.hasMethodAnnotation(OperationLog.class)) {
req.setAttribute("auditStart", System.currentTimeMillis());
}
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest req, HttpServletResponse res, Object handler, Exception ex) {
Long start = (Long) req.getAttribute("auditStart");
if (start != null) {
long duration = System.currentTimeMillis() - start;
// Persist audit log with duration and exception status
}
}
}
Execution Order with Interceptors and AOP
When both interceptors and AOP aspects are applied:
- Interceptor
preHandle() - AOP
@Beforeadvice - Controller method execution
- AOP
@AfterReturningadvice - Interceptor
postHandle() - Interceptor
afterCompletion() - AOP
@After(finally) advice
AOP @Around advice execution depends on proceed() invocation placement. @AfterThrowing advice executes if exceptions occur, before afterCompletion().