How to Implement Custom Logging with Spring AOP and Annotations

This guide explains how to create a custom Spring AOP logging solution by defining a @SystemCrmlog annotation, extracting its parameters via pointcuts, and persisting detailed log entries—including user, method, parameters, and execution results—to a database using aspect advice methods.

Java Interview Crash Guide
Java Interview Crash Guide
Java Interview Crash Guide
How to Implement Custom Logging with Spring AOP and Annotations

Introduction

When building a Spring project, logging requirements often exceed what simple AOP can capture; basic logs may only record table names or operation types. To store richer information, a custom annotation is introduced, allowing developers to embed desired log details and retrieve them through pointcuts for database insertion.

Spring AOP Basics

Reference: https://blog.csdn.net/yjt520557/article/details/84833508

Key terminology:

Aspect : Implemented via a regular class annotated with @Aspect (AspectJ style) or a generic class.

Joinpoint : Represents a method execution point.

Advice : Action executed at a specific joinpoint (e.g., @Around, @Before, @After).

Pointcut : Defines one or more methods that trigger advice; Spring uses AspectJ pointcut syntax by default.

Advice Types

@Before : Executes before a joinpoint; cannot prevent execution unless an exception is thrown.

@AfterReturning : Executes after successful completion of a joinpoint.

@AfterThrowing : Executes when a method throws an exception.

@After : Executes after a joinpoint regardless of outcome.

@Around : Wraps a joinpoint, allowing custom behavior before and after method invocation, and can control whether the original method proceeds.

Spring AOP Configuration Styles

XML style: Declares AOP support in XML.

AspectJ style: Uses annotation‑based configuration.

Creating a Custom Annotation

Define an annotation to hold log description and table name:

package com.ywj.log;
import java.lang.annotation.*;
/**
 * @interface SystemCrmlog
 * Custom annotation for AOP logging
 */
@Target({ElementType.PARAMETER, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface SystemCrmlog {
    String description() default "";
    String tableName() default "";
}

Aspect Class – Extracting Annotation Data

The aspect intercepts methods annotated with @SystemCrmlog, gathers request, user, and method details, builds a CrmLogMessage object, and persists it via Sys_logDao:

package com.ywj.log;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.text.SimpleDateFormat;
import java.util.*;

@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());
        new Sys_logDao().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());
        // Determine result based on returnValue type
        if (returnValue != null) {
            if (returnValue instanceof List) {
                log.setResult(((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("执行成功");
            }
        }
        new Sys_logDao().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);
        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();
        return new com.fasterxml.jackson.databind.ObjectMapper().writeValueAsString(arguments);
    }

    public HttpServletRequest getHttpServletRequest() {
        return ((org.springframework.web.context.request.ServletRequestAttributes)org.springframework.web.context.request.RequestContextHolder.getRequestAttributes()).getRequest();
    }
}

Log Entity Class

Represents a database record for each logged operation:

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 Class 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) return null;
        Object user = request.getSession().getAttribute(Constans.USER_KEY);
        return (Map<String, Object>) user;
    }
}

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 Example

Annotate any service method that requires logging:

@SystemCrmlog(description = "Performed login operation", tableName = Constans.USER_TABLENAME)
public void login(...) { ... }

After execution, a record similar to the following is stored in the database:

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaaopspringloggingCustom Annotation
Java Interview Crash Guide
Written by

Java Interview Crash Guide

Dedicated to sharing Java interview Q&A; follow and reply "java" to receive a free premium Java interview guide.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.