Implement Custom Logging with Spring AOP and Annotations
This guide explains how to create a custom Spring AOP annotation for detailed logging, defines the necessary annotation and aspect classes, shows how to extract method details, parameters and user info, store them in a database, and demonstrates required Spring XML configuration and usage examples.
Introduction
When using Spring to develop a project, logging often requires more than simple AOP; custom annotations can capture detailed information and store it in a database.
Spring AOP Overview
Basic concepts of Spring AOP include Aspect, Joinpoint, Advice, and Pointcut.
Advice Types
Before : executed before a join point, cannot prevent the method execution unless an exception is thrown.
AfterReturning : executed after a join point completes normally, i.e., without throwing an exception.
AfterThrowing : executed when a method throws an exception.
After : executed after a join point exits, regardless of outcome.
Around : surrounds a join point, can control whether the original method is invoked and modify the return value or exception.
Configuration Styles
XML style – declare AOP configuration in XML.
AspectJ style – use @Aspect and annotation‑based configuration.
Define Custom Annotation
package com.ywj.log;
import java.lang.annotation.*;
/**
* AOP log record custom annotation class
*/
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemCrmlog {
/** Log description – what operation was performed on which table */
String description() default "";
/** Table name involved in the operation */
String tableName() default "";
}Aspect Class
The aspect extracts annotation values via a pointcut, gathers request, user, and method information, builds a CrmLogMessage object and persists it.
package com.ywj.log;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ywj.log.biz.Sys_logBiz;
import com.ywj.log.dao.Sys_logDao;
import com.ywj.login.biz.Sys_UserBiz;
import com.ywj.login.dao.Sys_UserDao;
import com.ywj.login.dao.Sys_righDao;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;
@Aspect
@Component
public class SystemLogAspect {
@Pointcut("@annotation(com.ywj.log.SystemCrmlog)")
public void crmAspect() {}
@AfterThrowing(value = "crmAspect()", throwing = "ex")
public void afterThrowingMethod(JoinPoint joinPoint, Exception ex) throws Exception {
HttpServletRequest request = getHttpServletRequest();
WebUtil webUtil = new WebUtil();
Map<String, Object> user = webUtil.getUser(request);
CrmLogMessage log = new CrmLogMessage();
String context = getServiceMthodDescription(joinPoint);
String usr_name = "";
String rolename = "";
if (user != null) {
usr_name = user.get("usr_name").toString();
rolename = user.get("rolename").toString();
}
log.setUserName(usr_name);
log.setUserRole(rolename);
log.setContent(usr_name + context);
log.setRemarks(getServiceMthodParams(joinPoint));
log.setTableName(getServiceMthodTableName(joinPoint));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
log.setDateTime(sdf.format(new Date()));
log.setIp(request.getRemoteAddr());
log.setRequestUrl(request.getRequestURI());
log.setResult("执行失败");
log.setExString(ex.getMessage());
Sys_logDao sysLogDao = new Sys_logDao();
sysLogDao.addSys_log(log);
}
@AfterReturning(value = "crmAspect()", returning = "returnValue")
public void doCrmLog(JoinPoint joinPoint, Object returnValue) throws Exception {
HttpServletRequest request = getHttpServletRequest();
WebUtil webUtil = new WebUtil();
Map<String, Object> user = webUtil.getUser(request);
CrmLogMessage log = new CrmLogMessage();
String context = getServiceMthodDescription(joinPoint);
String usr_name = "";
String rolename = "";
if (user != null) {
usr_name = user.get("usr_name").toString();
rolename = user.get("rolename").toString();
}
log.setUserName(usr_name);
log.setUserRole(rolename);
log.setContent(usr_name + context);
log.setRemarks(getServiceMthodParams(joinPoint));
log.setTableName(getServiceMthodTableName(joinPoint));
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
log.setDateTime(sdf.format(new Date()));
log.setIp(request.getRemoteAddr());
log.setRequestUrl(request.getRequestURI());
if (returnValue != null) {
if (returnValue instanceof java.util.List) {
log.setResult(((java.util.List<?>) returnValue).size() > 0 ? "执行成功" : "执行成功");
} else if (returnValue instanceof Boolean) {
log.setResult(((Boolean) returnValue) ? "执行成功" : "执行失败");
} else if (returnValue instanceof Integer) {
log.setResult(((Integer) returnValue) > 0 ? "执行成功" : "执行失败");
} else {
log.setResult("执行成功");
}
}
Sys_logDao sysLogDao = new Sys_logDao();
sysLogDao.addSys_log(log);
}
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);
Method[] methods = targetClass.getMethods();
String description = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length == arguments.length) {
description = method.getAnnotation(SystemCrmlog.class).description();
break;
}
}
}
return description;
}
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);
Method[] methods = targetClass.getMethods();
String tableName = "";
for (Method method : methods) {
if (method.getName().equals(methodName)) {
Class<?>[] paramTypes = method.getParameterTypes();
if (paramTypes.length == arguments.length) {
tableName = method.getAnnotation(SystemCrmlog.class).tableName();
break;
}
}
}
return tableName;
}
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();
}
}Helper Classes
Log entity that maps to the database table.
package com.ywj.log;
/**
* Database log entity
*/
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 class to obtain the logged‑in user from the session.
package com.ywj.log;
import com.base.web.BaseAction;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;
/**
* Helper class to retrieve user information from the session
*/
public class WebUtil {
public Map<String, Object> getUser(HttpServletRequest request) {
Map<String, Object> attribute = null;
if (request != null) {
Object user = request.getSession().getAttribute(Constans.USER_KEY);
attribute = (Map<String, Object>) user;
}
return attribute;
}
}Spring XML 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
Add the custom annotation to any service method you wish to log.
@SystemCrmlog(description = "进行了登录操作", tableName = Constans.USER_TABLENAME)
public void login(...) { ... }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.
