Auto‑Inject User and Order IDs into Logs with Spring AOP and MDC
This article explains how to automatically include userId and orderId in log messages by storing them in MDC, defining a custom @UserLog annotation, and using Spring AOP to inject the values at runtime, eliminating manual log parameter handling.
Goal
Automatically fill userId and orderId in log messages without manual parameters.
Implementation Idea
Declare placeholders userId and orderId in the log pattern.
Store userId and orderId in a thread‑local (MDC) at the entry of business logic.
Use Spring AOP + a custom annotation to put these values into the thread context automatically.
Configure Log Pattern
Use %X{userId} and %X{orderId} in the pattern, e.g.
<?xml version="1.0" encoding="UTF-8"?>
<Configuration status="info">
<Appenders>
<Console name="consoleAppender" target="SYSTEM_OUT">
<PatternLayout pattern="%d{DEFAULT} [%t] %-5p - userId:%X{userId} orderId:%X{orderId} %m%n%ex" charset="UTF-8"/>
</Console>
</Appenders>
<Loggers>
<AsyncRoot level="info" includeLocation="true">
<appender-ref ref="consoleAppender"/>
</AsyncRoot>
</Loggers>
</Configuration>Use MDC to Store Variables
MDC (Mapped Diagnostic Context) is a thread‑local map provided by SLF4J. Put values with MDC.put("userId", userId) and MDC.put("orderId", orderId). They will be substituted into the pattern placeholders.
Define Annotation
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLog {
String userId() default "";
String orderId() default "";
}Define AOP Aspect
@Aspect
@Component
public class UserLogAspect {
@Pointcut("@annotation(UserLog) && execution(public * *(..))")
public void pointcut() {}
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
Object[] args = joinPoint.getArgs();
UserLog ann = method.getAnnotation(UserLog.class);
if (ann != null && args != null && args.length > 0) {
String userId = String.valueOf(PropertyUtils.getProperty(args[0], ann.userId()));
String orderId = String.valueOf(PropertyUtils.getProperty(args[0], ann.orderId()));
MDC.put("userId", userId);
MDC.put("orderId", orderId);
}
try {
return joinPoint.proceed();
} finally {
MDC.clear();
}
}
}Dependency
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>Business Service
@Service
public class OrderService {
private static final Logger log = LoggerFactory.getLogger(OrderService.class);
@UserLog(userId = "userId", orderId = "orderId")
public void orderPerform(UserOrder order) {
log.warn("订单履约完成");
}
@Data
public static class UserOrder {
String userId;
String orderId;
}
}Test
@Test
public void testUserLog() {
OrderService.UserOrder order = new OrderService.UserOrder();
order.setUserId("32894934895");
order.setOrderId("8497587947594859232");
orderService.orderPerform(order);
}Result
The log line contains the automatically injected IDs, for example:
2024-08-17 21:35:38,284 [main] WARN - userId:32894934895 orderId:8497587947594859232 订单履约完成Conclusion
Using a custom UserLog annotation together with Spring AOP and MDC lets you inject common parameters such as userId and orderId into every log entry automatically, reducing boilerplate and improving traceability.
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.
Java Backend Technology
Focus on Java-related technologies: SSM, Spring ecosystem, microservices, MySQL, MyCat, clustering, distributed systems, middleware, Linux, networking, multithreading. Occasionally cover DevOps tools like Jenkins, Nexus, Docker, and ELK. Also share technical insights from time to time, committed to Java full-stack development!
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.
