Master Spring Boot Request Logging, Wrappers, and AOP Utilities in One Guide

This article explains how to use Spring Boot's built‑in request logging, request/response wrappers, OncePerRequestFilter, and AOP utility classes such as AopContext, AopUtils, and ReflectionUtils, providing configuration snippets and practical code examples for backend developers.

macrozheng
macrozheng
macrozheng
Master Spring Boot Request Logging, Wrappers, and AOP Utilities in One Guide

Spring Boot provides many built‑in utilities that help developers efficiently develop and maintain applications.

1. Request Data Logging

Spring Boot offers a built‑in logging solution via AbstractRequestLoggingFilter. The commonly used implementation is CommonsRequestLoggingFilter, which can record request parameters, body, headers, and client information.

Enable it with a simple configuration:

@Configuration
public class RequestLoggingConfig {
    @Bean
    public CommonsRequestLoggingFilter logFilter() {
        CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
        filter.setIncludeQueryString(true);
        filter.setIncludePayload(true);
        filter.setIncludeHeaders(true);
        filter.setIncludeClientInfo(true);
        filter.setAfterMessagePrefix("REQUEST DATA-");
        return filter;
    }
}

Set the log level to DEBUG to capture detailed request information:

logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG

2. Request/Response Wrappers

2.1 What are request and response wrappers

In Spring Boot, request and response wrappers enhance the native HttpServletRequest and HttpServletResponse objects, allowing interception and modification of data during processing.

Request Wrapper

ContentCachingRequestWrapper

: Caches the request input stream so the body can be read multiple times.

Response Wrapper

ContentCachingResponseWrapper

: Caches the response output stream, enabling modification before the response is sent.

2.2 Usage Scenarios

Request logging.

Modifying request data before it reaches controllers.

Modifying response content before it is sent to the client.

Performance testing without affecting network I/O.

2.3 Example Code

Request Wrapper

import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class RequestWrapperFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        ContentCachingRequestWrapper requestWrapper = new ContentCachingRequestWrapper(request);
        // Process request data, e.g., log the body
        byte[] body = requestWrapper.getContentAsByteArray();
        filterChain.doFilter(requestWrapper, response);
    }
}

Response Wrapper

import org.springframework.web.filter.OncePerRequestFilter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class ResponseWrapperFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {
        ContentCachingResponseWrapper responseWrapper = new ContentCachingResponseWrapper(response);
        filterChain.doFilter(request, responseWrapper);
        // Process response data, e.g., add a signature header
        byte[] body = responseWrapper.getContentAsByteArray();
        responseWrapper.setHeader("X-Signature", "some-signature");
        responseWrapper.copyBodyToResponse();
    }
}

The OncePerRequestFilter base class ensures the filter runs only once per request lifecycle, preventing duplicate processing.

3. OncePerRequestFilter

3.1 Overview

OncePerRequestFilter

is a Spring filter base class that guarantees single execution per request, even when the request is forwarded or included.

Single execution per request lifecycle.

Built‑in support for request and response wrappers.

Simplifies filter code by handling registration and execution.

Easy to extend by overriding doFilterInternal.

3.2 Typical Use Cases

Request logging without duplicate entries.

Pre‑processing or modifying request data.

Post‑processing or modifying response data.

Security checks such as authentication and authorization.

Wrapping requests and responses for caching.

Performance monitoring.

Centralized exception handling.

4. AOP Utility Classes

4.1 AopContext

AopContext

provides access to the current proxy and target objects. Common methods: getTargetObject(): Retrieve the target object. currentProxy(): Retrieve the current proxy.

Example: using AopContext.currentProxy() to invoke a transactional method from the same class.

public void noTransactionTask(String keyword) {
    // Call transactional method via proxy to keep @Transactional effective
    ((YourClass) AopContext.currentProxy()).transactionTask(keyword);
}

@Transactional
void transactionTask(String keyword) {
    try { Thread.sleep(5000); } catch (InterruptedException e) { /* handle */ }
    System.out.println(keyword);
}

4.2 AopUtils

AopUtils

offers static helpers for AOP operations, such as obtaining the target object and checking proxy types.

getTargetObject()
isJdkDynamicProxy(Object)
isCglibProxy(Object)

Example checking for a CGLIB proxy:

if (AopUtils.isCglibProxy(myService)) {
    System.out.println("This is a CGLIB proxy object");
}

4.3 ReflectionUtils

ReflectionUtils

simplifies reflection tasks such as making fields accessible, reading field values, and invoking methods.

makeAccessible(Field)
getField(Field, Object)
invokeMethod(Method, Object, Object...)

Example retrieving a private map field:

Field field = ReflectionUtils.findField(ExampleBean.class, "mapAttribute");
ReflectionUtils.makeAccessible(field);
Object value = ReflectionUtils.getField(field, bean);
System.out.println(value);
Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

aopbackend-developmentSpring BootFiltersRequest Logging
macrozheng
Written by

macrozheng

Dedicated to Java tech sharing and dissecting top open-source projects. Topics include Spring Boot, Spring Cloud, Docker, Kubernetes and more. Author’s GitHub project “mall” has 50K+ stars.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.