Spring AOP — Behaviour Around Methods
The operations team asks: "Log how long every service method in library-service takes." You could paste timing code into forty methods, and then remove it from forty methods next month. Some concerns cut across the whole app: timing, logging, transactions, security checks. Aspect-Oriented Programming (AOP) lets you write them once.
The rule
Write the cross-cutting code once; Spring wraps it around the methods you pick.
The vocabulary is small:
- Aspect — a class that holds the cross-cutting code.
- Advice — the code itself and when it runs:
@Before,@AfterReturning,@AfterThrowing,@After, or@Around(which surrounds the call). - Pointcut — an expression that picks which methods to wrap.
- Join point — one place the advice runs. In Spring AOP, that is always a method call on a bean.
@Aspect
@Component
public class TimingAspect {
private static final Logger log = LoggerFactory.getLogger(TimingAspect.class);
@Around("execution(* com.example.library.service..*.*(..))")
public Object time(ProceedingJoinPoint call) throws Throwable {
long start = System.nanoTime();
try {
return call.proceed(); // run the real method
} finally {
log.info("{} took {} µs", call.getSignature(),
(System.nanoTime() - start) / 1000);
}
}
}With the spring-boot-starter-aop dependency on the classpath, every public method of every bean in the service package is now timed, and LoanService has not changed at all.
How it works: Spring does not edit your class. It creates a proxy, a stand-in object that looks like LoanService, and injects the proxy wherever LoanService is asked for. A call arrives at the proxy, the proxy runs the advice, and the advice calls the real method via proceed(). You already use this without knowing: @Transactional and @PreAuthorize are built on the same proxies.
The shortcut
To predict whether advice runs, ask one question: "Did the call come through the proxy?" Calls from other beans arrive through the proxy. A call from inside the same object, such as this.renew() from within borrow(), goes straight to the real object and skips the proxy.
The setup
BookControllercallsloanService.borrow(). Inside,borrow()callsthis.renew().
This self-call trap catches @Transactional too: a transactional method called from the same class runs without its own transaction settings.
Drills
Answer fast — trust the rule.
Which of these is a cross-cutting concern?
In Spring AOP, what does a pointcut do?
Which advice type can run code both before and after a method and decide whether to call it?
borrow() calls this.renew() in the same bean. Does timing advice on renew() run for that call?
Remember
- Write the cross-cutting code once; Spring wraps it around the methods you pick.
- Ask "did the call come through the proxy?" If not, no advice runs.
- Trap: self-calls skip aspects,
@Transactionalincluded.
