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.

Programmer DD
Programmer DD
Programmer DD
Implement Custom Annotation Logging with Spring AOP

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.

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.

JavadatabaseloggingCustom Annotationspring-aopaspectj
Programmer DD
Written by

Programmer DD

A tinkering programmer and author of "Spring Cloud Microservices in Action"

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.