Implementing Business Operation Logging with Spring AOP in a Spring Boot Application
This article explains how to design and implement a business operation logging feature using Spring AOP in a Spring Boot project, covering requirement analysis, anti‑pattern pitfalls, AOP design, environment and dependency setup, database schema, annotation and aspect code, and testing procedures.
Preface
The author finally writes about a simple requirement—recording and querying business operation logs—while recalling a poorly implemented solution that motivated the redesign.
Requirement Description and Analysis
Clients need to log who performed which operation, when, the request and response payloads, and optionally allow a one‑click rollback.
System Log
System logs capture program execution steps (debug, info, warn, error) for developers or ops to troubleshoot issues.
Operation Log
Operation logs record actual business actions (user, time, function, type, description, request/response messages) and are stored in a database for users or administrators.
Key functional requirements:
Record fields: operator, time, function, log type, description, request message, previous message.
Provide a visual page for querying and tracing important operations.
Allow rollback of erroneous operations when needed.
Anti‑pattern Implementation
The initial approach hard‑coded log collection in every controller method, duplicated code, and tightly coupled logging with business logic, making maintenance painful.
@RestController
@Slf4j
@BusLog(name = "Personnel Management")
@RequestMapping("/person")
public class PersonController2 {
@Autowired
private IPersonService personService;
@Autowired
private IBusLogService busLogService;
// add person
@PostMapping
public Person add(@RequestBody Person person) {
try {
Person result = this.personService.registe(person);
this.saveLog(person);
log.info("// add person completed");
} catch (Exception e) {
this.saveExceptionLog(e);
}
return result;
}
}Design Idea
Using AOP is the clean solution:
Define a custom annotation @BusLog with attributes such as function name and description.
Annotate target methods (or classes) that require logging.
Create a pointcut for methods annotated with @BusLog and implement an aspect that records the log after method execution.
Spring AOP
AOP allows adding cross‑cutting concerns without modifying source code, providing fine‑grained control (before, after, around, exception, return) and can be applied at controller or service layers.
Filter and HandlerInterceptor
Filters and interceptors are limited to servlet environments and cannot modify request/response payloads, whereas Spring AOP works across any layer.
Comparison
Scope: Filter → servlet container; Interceptor → Spring MVC; Spring AOP → any Spring bean.
Granularity: Filter (coarse), Interceptor (pre/post), Spring AOP (most fine‑grained, can alter return values).
Implementation Plan
Environment Configuration
JDK 1.8, IntelliJ IDEA 2020.1
Spring Boot 2.3.9.RELEASE
mybatis-spring-boot-starter 2.1.4
Dependency Configuration
org.springframework.boot
spring-boot-starter-aopTable Structure Design
create table if not exists bus_log (
id bigint auto_increment comment '自增id' primary key,
bus_name varchar(100) null comment '业务名称',
bus_descrip varchar(255) null comment '业务操作描述',
oper_person varchar(100) null comment '操作人',
oper_time datetime null comment '操作时间',
ip_from varchar(50) null comment '操作来源ip',
param_file varchar(255) null comment '操作参数报文文件'
) comment '业务操作日志' default charset='utf8';Code Implementation
1. Define the @BusLog annotation.
/**
* Business log annotation
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface BusLog {
String name() default ""; // function name
String descrip() default ""; // description
}2. Annotate controller methods.
@RestController
@Slf4j
@BusLog(name = "Personnel Management")
@RequestMapping("/person")
public class PersonController {
@Autowired
private IPersonService personService;
@PostMapping
@BusLog(descrip = "Add a single person")
public Person add(@RequestBody Person person) {
Person result = personService.registe(person);
log.info("// add person completed");
return result;
}
// other CRUD methods similarly annotated
}3. Implement the aspect that writes log entries and saves request payloads to files.
@Component
@Aspect
@Slf4j
public class BusLogAop implements Ordered {
@Autowired
private BusLogDao busLogDao;
@Pointcut("@annotation(com.fanfu.anno.BusLog)")
public void pointcut() {}
@Around("pointcut()")
public Object around(ProceedingJoinPoint pjp) throws Throwable {
Object result = pjp.proceed();
// retrieve annotation info, serialize arguments, write to file, insert DB record
return result;
}
@Override
public int getOrder() { return 1; }
}Testing
Debugging Method
Use IntelliJ IDEA's built‑in HTTP client (Tools → HTTP Client → Test RESTful Web Service) as an alternative to Postman.
Verification Result
Screenshot examples show successful requests and logged entries.
Conclusion
The business operation log captures function name, description, operator, timestamp, and parameter payloads; storing payloads in files keeps the database lightweight while still enabling precise rollback when needed.
Selected Java Interview Questions
A professional Java tech channel sharing common knowledge to help developers fill gaps. Follow us!
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.