Backend Development 13 min read

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:

<code>@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;
    }
}
</code>

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

<code>logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUG
</code>

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

<code>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);
    }
}
</code>

Response Wrapper

<code>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();
    }
}
</code>

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.

<code>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);
}
</code>

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:

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

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:

<code>Field field = ReflectionUtils.findField(ExampleBean.class, "mapAttribute");
ReflectionUtils.makeAccessible(field);
Object value = ReflectionUtils.getField(field, bean);
System.out.println(value);
</code>
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

login 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.