Unlock Spring Boot’s Powerful Built‑In Features You’re Not Using
This article walks through Spring Boot’s built‑in utilities—including request logging with CommonsRequestLoggingFilter, request/response wrappers, the OncePerRequestFilter base class, and AOP helpers like AopContext, AopUtils, and ReflectionUtils—showing how to configure and apply them in real code.
Request Data Logging
Spring Boot includes AbstractRequestLoggingFilter with the subclass CommonsRequestLoggingFilter. Defining a bean enables logging of query strings, payloads, headers, and client information, and allows a custom message prefix.
@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 logger level to DEBUG for org.springframework.web.filter.CommonsRequestLoggingFilter to record detailed request information.
logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUGRequest/Response Wrappers
What they are
ContentCachingRequestWrappercaches the request input stream, allowing multiple reads of the request body. ContentCachingResponseWrapper caches the response output stream, enabling modification before the response is committed.
Typical use cases
Request logging : record headers, parameters, and body before and after processing.
Request data modification : alter headers or body before the controller handles the request.
Response content modification : add or change headers, or sign the response body before it reaches the client.
Performance testing : cache request/response data to benchmark without affecting real network I/O.
Example: Request wrapper filter
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);
// optional processing, e.g., logging
byte[] body = requestWrapper.getContentAsByteArray();
// log body ...
filterChain.doFilter(requestWrapper, response);
}
}Example: Response wrapper filter
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);
// optional processing, e.g., adding a signature
byte[] body = responseWrapper.getContentAsByteArray();
responseWrapper.setHeader("X-Signature", "some-signature");
responseWrapper.copyBodyToResponse();
}
} OncePerRequestFilterguarantees that the filter logic runs only once per request lifecycle, preventing duplicate processing during forwards or includes.
OncePerRequestFilter
Spring‑provided base class that extends Filter with the following characteristics:
Single execution : ensures the filter runs only once per request, regardless of forwards or includes.
Built‑in support for request/response wrappers : simplifies caching and modification of request and response data.
Code simplification : developers inherit the class to avoid repetitive filter registration code.
Easy extensibility : overriding doFilterInternal lets developers add custom logic without handling registration or execution count.
Typical scenarios include request logging, request data modification, response alteration, security checks, performance monitoring, and exception handling, all executed exactly once per request.
AOP Utilities
AopContext
Provides access to the current proxy and its target object. Key methods: getTargetObject(): obtain the target object. currentProxy(): obtain the current proxy, useful for invoking another method in the same class that is annotated with @Transactional without losing proxy behavior.
public void noTransactionTask(String keyword) {
((YourClass) AopContext.currentProxy()).transactionTask(keyword);
}
@Transactional
void transactionTask(String keyword) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// handle exception
}
System.out.println(keyword);
}AopUtils
Static helpers for AOP proxy inspection. getTargetObject(): retrieve the target from a proxy. isJdkDynamicProxy(Object): determine if the object is a JDK dynamic proxy. isCglibProxy(Object): determine if the object is a CGLIB proxy.
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
public class AopUtilsExample {
public static void main(String[] args) {
MyService myService = ...; // assumed proxied
if (AopUtils.isCglibProxy(myService)) {
System.out.println("This is a CGLIB proxy object");
}
}
}ReflectionUtils
Convenient methods for Java reflection, reducing boilerplate. makeAccessible(Field): make a private field accessible. getField(Field, Object): read a field value. invokeMethod(Method, Object, ...): invoke a method reflectively.
import org.springframework.util.ReflectionUtils;
import java.lang.reflect.Field;
import java.util.Map;
public class ReflectionUtilsExample {
public static void main(String[] args) throws Exception {
ExampleBean bean = new ExampleBean();
bean.setMapAttribute(new HashMap<>());
Field field = ReflectionUtils.findField(ExampleBean.class, "mapAttribute");
ReflectionUtils.makeAccessible(field);
Object value = ReflectionUtils.getField(field, bean);
System.out.println(value);
}
static class ExampleBean {
private Map<String, String> mapAttribute;
public void setMapAttribute(Map<String, String> mapAttribute) {
this.mapAttribute = mapAttribute;
}
}
}These built‑in Spring components enable developers to add logging, modify requests/responses, enforce single‑execution filters, and work with AOP proxies without writing boilerplate code.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Programmer XiaoFu
xiaofucode.com – a programmer learning guide driven by the pursuit of profit
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
