Implement Custom Annotation Logging with Spring AOP
This guide explains how to create a custom annotation and an Aspect in Spring to capture detailed operation logs—including description, table name, parameters, user info, and execution result—and persist them to a database, covering AOP terminology, configuration styles, and complete code examples.
Introduction
When developing a Spring project, simple AOP logging often cannot record detailed information such as operation description or table name. By defining a custom annotation and using a pointcut to capture its parameters, you can store comprehensive logs in a database.
Spring AOP Terminology
Aspect : a class annotated with @Aspect that contains cross‑cutting logic.
Joinpoint : a specific method execution point.
Advice : the action taken at a joinpoint (e.g., @Before, @AfterReturning, @AfterThrowing, @After, @Around).
Pointcut : an expression that selects one or more joinpoints, often using AspectJ syntax.
Configuration Styles
Spring AOP can be configured either via XML (using <aop:aspectj-autoproxy/>) or by using the AspectJ annotation style directly in Java code.
Custom Annotation Definition
package com.ywj.log;
import java.lang.annotation.*;
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemCrmlog {
String description() default ""; // operation description
String tableName() default ""; // target table name
}Aspect Implementation
The SystemLogAspect class is annotated with @Aspect and @Component. It defines a pointcut that matches the custom annotation and provides several advice methods: @AfterThrowing: records failure details, captures exception message, user info, request IP, URL, and saves the log. @AfterReturning: records successful execution, determines success based on the returned object type (List, Boolean, Integer, etc.), and saves the log.
Both advice methods retrieve the current HttpServletRequest, obtain user data via WebUtil, build a CrmLogMessage instance, and persist it with Sys_logDao.
Helper Methods
private String getServiceMthodDescription(JoinPoint joinPoint) throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class<?> targetClass = Class.forName(targetName);
for (Method method : targetClass.getMethods()) {
if (method.getName().equals(methodName) &&
method.getParameterTypes().length == arguments.length) {
return method.getAnnotation(SystemCrmlog.class).description();
}
}
return "";
}
private String getServiceMthodTableName(JoinPoint joinPoint) throws Exception {
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Class<?> targetClass = Class.forName(targetName);
for (Method method : targetClass.getMethods()) {
if (method.getName().equals(methodName) &&
method.getParameterTypes().length == arguments.length) {
return method.getAnnotation(SystemCrmlog.class).tableName();
}
}
return "";
}
private String getServiceMthodParams(JoinPoint joinPoint) throws Exception {
Object[] arguments = joinPoint.getArgs();
ObjectMapper om = new ObjectMapper();
return om.writeValueAsString(arguments);
}
public HttpServletRequest getHttpServletRequest() {
RequestAttributes ra = RequestContextHolder.getRequestAttributes();
ServletRequestAttributes sra = (ServletRequestAttributes) ra;
return sra.getRequest();
}Log Entity
package com.ywj.log;
public class CrmLogMessage {
private Integer logid;
private String userName;
private String userRole;
private String content;
private String remarks;
private String tableName;
private String dateTime;
private String resultValue;
private String ip;
private String requestUrl;
private String result;
private String exString;
// getters, setters, constructors, toString omitted for brevity
}Utility for Session User
package com.ywj.log;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
public class WebUtil {
public Map<String, Object> getUser(HttpServletRequest request) {
if (request != null) {
Object user = request.getSession().getAttribute(Constans.USER_KEY);
return (Map<String, Object>) user;
}
return null;
}
}Spring Configuration
<aop:aspectj-autoproxy proxy-target-class="true"/>
<context:component-scan base-package="com.ywj.log"/>
<context:component-scan base-package="com.*.*.biz.impl"/>Usage
Annotate any service method you want to log:
@SystemCrmlog(description = "performed login operation", tableName = Constans.USER_TABLENAME)
public void login(...) { ... }The aspect will automatically capture the description, table name, method parameters (as JSON), user information, request details, execution result, and any exception, then persist a CrmLogMessage record to the database.
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 DD
A tinkering programmer and author of "Spring Cloud Microservices in Action"
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.
