Backend Development 15 min read

Designing Business Operation Logging with AOP, SpEL, and Binlog: From Basic to Advanced Solutions

This article explores the evolution of business operation logging in a Java backend, starting from a simple AOP‑annotation approach, advancing to AOP combined with Spring Expression Language for richer context, and finally leveraging MySQL binlog with time‑window processing to achieve comprehensive, low‑intrusion audit trails.

Selected Java Interview Questions
Selected Java Interview Questions
Selected Java Interview Questions
Designing Business Operation Logging with AOP, SpEL, and Binlog: From Basic to Advanced Solutions

In a recent project the system sits at the core of a business chain, receiving upstream data and forwarding processed user‑operation data downstream, prompting the need for full‑lifecycle business operation logs to improve troubleshooting and provide analytical tools.

The benefits of business operation logs include audit and compliance, security (intrusion detection and post‑incident analysis), error diagnosis and system monitoring, user behavior analysis, data recovery, and process improvement.

Solution 1.0: AOP Aspect + Annotation

Using Spring AOP and a custom @Loggable annotation, developers can minimally intrude into business methods and automatically record execution details.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Loggable {
    String value() default ""; // additional attributes can be added
}

An aspect intercepts methods annotated with @Loggable and logs execution time.

@Aspect
@Component
public class LoggingAspect {
    @Around("@annotation(loggable)")
    public Object logExecutionTime(ProceedingJoinPoint joinPoint, Loggable loggable) throws Throwable {
        long start = System.currentTimeMillis();
        Object proceed = joinPoint.proceed();
        long executionTime = System.currentTimeMillis() - start;
        logger.info(joinPoint.getSignature() + " executed in " + executionTime + "ms");
        return proceed;
    }
}

Configuration enables proxying and demonstrates usage in a service class.

@Configuration
@EnableAspectJAutoProxy
public class AopConfig { }

public class SomeService {
    @Loggable
    public void someBusinessMethod(Object someParam) {
        // business logic
    }
}

While functional, this approach suffers from limited log granularity, lack of business‑level context, and difficulty handling cascaded operations.

Solution 2.0: AOP Aspect + SpEL

To enrich log content, the annotation is extended to include fields such as success, fail, operator, type, subType, bizNo, extra, and actionType, whose values are expressed using Spring Expression Language (SpEL).

@Repeatable(LogRecords.class)
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface LogRecord {
    String success();
    String fail() default "";
    String operator() default "";
    String type();
    String subType() default "";
    String bizNo();
    String extra() default "";
    String actionType();
}

A parser evaluates SpEL expressions at runtime, allowing dynamic insertion of method parameters, return values, and other context into the log.

ExpressionParser parser = new SpelExpressionParser();
Expression expression = parser.parseExpression("'Hello '.concat(#param)");
String result = expression.getValue(context, String.class);

The upgraded solution reduces repetitive code but introduces many custom annotations and still requires agreement between product and development on log semantics.

Solution 3.0: Binlog + Time Window

Moving the logging responsibility to the database layer, MySQL binlog records every data‑change event. By applying a sliding time‑window (e.g., 1‑minute tumbling windows) similar to Flink, unordered binlog entries can be grouped and correlated, handling multi‑table cascades and associating user information.

Key data structures for parsing binlog rows are defined as follows:

@Data
public static class RowChange {
    private int tableId;
    private List
rowDatas;
    private String eventType;
    private boolean isDdl;
}

@Data
public static class RowDatas {
    private List
afterColumns;
    private List
beforeColumns;
}

@Data
public static class DataColumn {
    private int sqlType;
    private boolean isNull;
    private String mysqlType;
    private String name;
    private boolean isKey;
    private int index;
    private boolean updated;
    private String value;
}

The architecture combines binlog parsing, window aggregation, and optional ORM interception to capture the operator field, achieving a low‑intrusion, centralized logging mechanism that can be reused across services.

Although this approach greatly improves data‑change visibility, it still faces challenges such as handling non‑transactional binlog streams, integrating external data sources, and preserving fine‑grained business semantics.

In conclusion, logging strategies evolve from application‑level AOP to expression‑driven annotations and finally to database‑level change capture, each trade‑offing implementation complexity, intrusiveness, and granularity; the optimal solution depends on the specific system’s requirements and constraints.

backendJavaAOPSpringSPELLoggingbinlog
Selected Java Interview Questions
Written by

Selected Java Interview Questions

A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!

0 followers
Reader feedback

How this landed with the community

login 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.