Mastering Business Operation Logging: From AOP to Binlog with Spring
This article explores comprehensive strategies for capturing business operation logs in a Spring‑based system, comparing three solutions—from a simple AOP‑annotation approach, through an enhanced AOP + SpEL method, to a robust Binlog‑plus‑time‑window architecture—while weighing their advantages, drawbacks, and implementation details.
Background
In a recent project the system needed full‑lifecycle logging of business operations because it sits at the core of the data flow, receiving upstream data and forwarding it downstream. Detailed logs improve troubleshooting, auditing, monitoring, and provide valuable business insights.
Benefits of Business Operation Logs
Audit & Compliance : Track who changed what and when.
Security : Detect intrusions and perform post‑incident analysis.
Error Diagnosis & Monitoring : Aid fault isolation and performance monitoring.
User Behavior Analysis : Derive business insights and improve customer service.
Data Recovery : Assist backup and restore processes.
Process Improvement : Optimize workflows based on logged data.
Solution 1.0 – AOP + Annotation
Using Spring AOP and a custom @Loggable annotation provides a low‑intrusion way to capture method execution details.
@Retention(RetentionPolicy.RUNTIME)</code>
<code>@Target(ElementType.METHOD)</code>
<code>public @interface Loggable {</code>
<code> String value() default "";</code>
<code> // additional attributes such as operation type, level, etc.</code>
<code>} @Aspect</code>
<code>@Component</code>
<code>public class LoggingAspect {</code>
<code> @Around("@annotation(loggable)")</code>
<code> public Object logExecutionTime(ProceedingJoinPoint joinPoint, Loggable loggable) throws Throwable {</code>
<code> long start = System.currentTimeMillis();</code>
<code> Object result = joinPoint.proceed();</code>
<code> long executionTime = System.currentTimeMillis() - start;</code>
<code> logger.info(joinPoint.getSignature() + " executed in " + executionTime + "ms");</code>
<code> return result;</code>
<code> }</code>
<code>}Configuration enables AOP auto‑proxying and demonstrates usage on a service method annotated with @Loggable.
Solution 2.0 – AOP + SpEL
To enrich log content, SpEL expressions are introduced, allowing dynamic insertion of business context such as IDs and operation types.
@Value("#{mq.topic}")</code>
<code>public String mqTopic;</code>
<code>@Value("#{T(java.lang.Math).random() * 100.0}")</code>
<code>private double randomNumber;A more detailed annotation is defined:
@Repeatable(LogRecords.class)</code>
<code>@Target({ElementType.METHOD, ElementType.TYPE})</code>
<code>@Retention(RetentionPolicy.RUNTIME)</code>
<code>@Inherited</code>
<code>@Documented</code>
<code>public @interface LogRecord {</code>
<code> String success();</code>
<code> String fail() default "";</code>
<code> String operator() default "";</code>
<code> String type();</code>
<code> String subType() default "";</code>
<code> String bizNo();</code>
<code> String extra() default "";</code>
<code> String actionType();</code>
<code>}A parser evaluates SpEL expressions at runtime, enabling logs such as “User X modified project ID=001”. The approach reduces boilerplate code but introduces many annotation attributes.
Solution 3.0 – Binlog + Time Window
Leveraging MySQL binlog captures low‑level data changes. To handle unordered binlog entries and multi‑table cascades, a sliding time‑window (e.g., 1‑minute tumbling window) groups events, while reference fields link related rows.
@Data
public static class RowChange {</code>
<code> private int tableId;</code>
<code> private List<RowDatas> rowDatas;</code>
<code> private String eventType;</code>
<code> private boolean isDdl;</code>
<code>}</code>
<code>@Data
public static class RowDatas {</code>
<code> private List<DataColumn> afterColumns;</code>
<code> private List<DataColumn> beforeColumns;</code>
<code>}</code>
<code>@Data
public static class DataColumn {</code>
<code> private int sqlType;</code>
<code> private boolean isNull;</code>
<code> private String mysqlType;</code>
<code> private String name;</code>
<code> private boolean isKey;</code>
<code> private int index;</code>
<code> private boolean updated;</code>
<code> private String value;</code>
<code>}The architecture combines binlog ingestion, windowed aggregation, and optional ORM interceptors to enrich logs with operator information.
Comparative Summary
Solution 1: Simple, low‑intrusion, but limited context and hard to handle cascades.
Solution 2: Adds rich, customizable data via SpEL; however, annotation proliferation increases complexity.
Solution 3: Provides deep data‑change visibility and centralizes logging, yet may miss high‑level business semantics and requires handling of non‑application‑generated binlog events.
Overall, the evolution demonstrates a trade‑off between implementation effort, log granularity, and system invasiveness. Choosing the right approach depends on the specific auditing, monitoring, and compliance requirements of the project.
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.
