Unlock Spring Boot’s Hidden Power: Built‑in Tools Every Backend Engineer Should Master
This article walks through Spring Boot’s most useful built‑in features—including request logging, content‑caching wrappers, OncePerRequestFilter, AOP utilities, starter auto‑configuration, flexible property binding, async scheduling, Actuator monitoring, and SpEL expressions—showing how to apply them with concise code examples to boost productivity and reliability.
Hello, I’m Peng Lei
1. Request Data Full‑Chain Tracing: CommonsRequestLoggingFilter
During debugging and monitoring, logging the complete request information is essential. Spring Boot’s CommonsRequestLoggingFilter enables detailed request logging with minimal configuration.
Core Capabilities
Multi‑dimensional data collection : supports logging query string ( includeQueryString), request body ( includePayload), headers ( includeHeaders) and client IP.
Flexible log format : customize log prefix via setAfterMessagePrefix for easier classification.
Quick Enable
1. Configure the filter :
@Configuration
public class RequestLoggingConfig {
@Bean
public CommonsRequestLoggingFilter logFilter() {
CommonsRequestLoggingFilter filter = new CommonsRequestLoggingFilter();
filter.setIncludeQueryString(true); // include query parameters
filter.setIncludePayload(true); // include request body
filter.setMaxPayloadLength(1024); // limit body size to avoid overflow
filter.setAfterMessagePrefix("[REQUEST DATA] ");
return filter;
}
}2. Set log level in application.properties:
logging.level.org.springframework.web.filter.CommonsRequestLoggingFilter=DEBUGLog Example
[REQUEST DATA] POST /api/user, client=192.168.1.1, headers=[Content-Type:application/json], payload={"username":"test","email":"[email protected]"}2. Request/Response Flexible Manipulation: ContentCaching Wrappers
The native HttpServletRequest and HttpServletResponse streams can be read only once, which limits scenarios such as logging and business logic separation. Spring provides ContentCachingRequestWrapper and ContentCachingResponseWrapper to cache the streams.
Core Wrappers
Request wrapper : caches request body bytes, allowing multiple reads. Typical use case – log the request and still let the controller parse the body.
Response wrapper : caches response output, enabling modifications (e.g., adding signatures) before the response is committed.
Practical Filter Implementation
// Request wrapper filter
@Component
public class RequestLogFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
byte[] requestBody = wrappedRequest.getContentAsByteArray();
log.debug("Received request body: {}", new String(requestBody));
filterChain.doFilter(wrappedRequest, response);
}
}
// Response wrapper filter
@Component
public class ResponseSignFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
ContentCachingResponseWrapper wrappedResponse = new ContentCachingResponseWrapper(response);
filterChain.doFilter(request, wrappedResponse);
byte[] responseBody = wrappedResponse.getContentAsByteArray();
String signature = Base64.getEncoder().encodeToString(responseBody);
wrappedResponse.setHeader("X-Response-Signature", signature);
wrappedResponse.copyBodyToResponse();
}
}3. Single‑Execution Guarantee: OncePerRequestFilter Base Class
In forward or include scenarios, ordinary filters may execute multiple times, causing duplicated logic. Extending OncePerRequestFilter ensures the filter runs only once per request lifecycle, simplifying logging, security checks, or performance monitoring.
Core Advantages
Avoid duplicate processing : internal shouldNotFilter logic prevents repeated execution.
Simplify development : only override doFilterInternal without manual request‑identification handling.
Typical Use Cases
Logging – avoid repeated log entries during forwards.
Security – ensure JWT validation runs once.
Performance monitoring – record accurate request latency.
4. AOP Development Helpers: Three Utility Classes
Spring AOP relies on three auxiliary classes that simplify proxy access and reflection.
1. AopContext – proxy accessor
When a method within the same class calls another @Transactional method, the transaction may be bypassed. AopContext.currentProxy() retrieves the current proxy to ensure the advice is applied.
public class ServiceImpl {
@Transactional
public void innerMethod() { /* transaction logic */ }
public void outerMethod() {
// Direct call would skip transaction
((ServiceImpl) AopContext.currentProxy()).innerMethod();
}
}2. AopUtils – proxy type checker
if (AopUtils.isJdkDynamicProxy(proxyObject)) {
// handle JDK proxy
} else if (AopUtils.isCglibProxy(proxyObject)) {
// handle CGLIB proxy
}3. ReflectionUtils – reflection simplifier
// Access private field
Field field = ReflectionUtils.findField(MyClass.class, "privateField");
ReflectionUtils.makeAccessible(field);
Object value = ReflectionUtils.getField(field, instance);
// Invoke private method
Method method = ReflectionUtils.findMethod(MyClass.class, "privateMethod", String.class);
ReflectionUtils.invokeMethod(method, instance, "arg");5. Dependency Management Magic: Starter Auto‑Configuration
Spring Boot’s starter mechanism provides a one‑stop dependency declaration. Adding a starter (e.g., spring-boot-starter-web) automatically pulls in Tomcat, Spring MVC, Jackson, etc., while the parent spring-boot-dependencies ensures version alignment.
Common Starters
Web development – spring-boot-starter-web JDBC – spring-boot-starter-jdbc MongoDB – spring-boot-starter-data-mongodb Security – spring-boot-starter-security Kafka – spring-boot-starter-kafka Custom starters can be created by adding a spring.factories entry under src/main/resources/META-INF and providing an auto‑configuration class annotated with conditional annotations such as @ConditionalOnClass and @ConditionalOnMissingBean.
6. Configuration Simplification: Auto‑Configuration & Placeholders
Spring Boot’s auto‑configuration ( @EnableAutoConfiguration) scans the classpath and creates beans like DataSource or MongoTemplate based on present starters. Configuration properties can be bound to POJOs with @ConfigurationProperties, eliminating hard‑coded values.
@Configuration
@ConfigurationProperties(prefix = "app")
public class AppConfig {
private String env;
private DatabaseConfig database;
// getters & setters
public static class DatabaseConfig {
private String url;
private String username;
// ...
}
}Placeholders (${…}) and @Value allow dynamic injection of environment variables or default values.
@Value("${app.env:dev}")
private String environment;7. Asynchronous & Scheduled Tasks
Annotating methods with @Async (enabled via @EnableAsync) runs them in a separate thread pool, while @Scheduled defines cron‑based or fixed‑delay jobs.
@Service
public class AsyncService {
@Async("customExecutor")
public CompletableFuture<Void> processAsyncTask(String taskId) {
// time‑consuming logic
return CompletableFuture.completedFuture(null);
}
}
@Configuration
@EnableAsync
public class AsyncConfig {
@Bean("customExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(5);
executor.setMaxPoolSize(10);
executor.setQueueCapacity(20);
executor.initialize();
return executor;
}
} @Service
public class ScheduledService {
@Scheduled(cron = "0 0 1 * * ?")
public void dailyCleanup() { /* cleanup logic */ }
@Scheduled(fixedDelay = 5000)
public void periodicSync() { /* sync logic */ }
}8. Monitoring & Diagnostics: Actuator
Spring Boot Actuator supplies production‑ready endpoints such as /health, /metrics, /env, /threaddump, and /logfile. Adding spring-boot-starter-actuator and exposing the desired endpoints in application.yml enables health checks, metric collection, and runtime configuration inspection.
Custom Metrics
@Autowired
private MeterRegistry meterRegistry;
public void recordOrder(String status) {
meterRegistry.counter("order.processed", "status", status).increment();
}9. Expression Power: Spring Expression Language (SpEL)
SpEL allows dynamic evaluation in bean definitions, conditional annotations, and security expressions.
<bean id="userService" class="com.example.UserService">
<property name="defaultTimeout" value="#{T(java.lang.Integer).parseInt('1000')}"/>
</bean> @ConditionalOnExpression("${app.env} == 'prod' && @environment.getProperty('server.port') == 8080")
public class ProdConfig { } @PreAuthorize("hasRole('ADMIN') or @accessService.hasPermission(#userId)")
public void deleteUser(Long userId) { /* ... */ }Architect's Tech Stack
Java backend, microservices, distributed systems, containerized programming, and more.
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.
