Pebellslearn by building
0%
RoadmapsMatrixCoursesSandboxSign in
The Spring Core  ›  Lesson

Spring AOP — Behaviour Around Methods

Spring AOP 14 minAspects hold cross-cutting code that Spring runs around selected bean methods through proxies, so calls that bypass the proxy are not advised.

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.

Why isn't renew() being timed?Step 1 of 4
  1. The setup

    BookController calls loanService.borrow(). Inside, borrow() calls this.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.

quick drill

Which of these is a cross-cutting concern?

quick drill

In Spring AOP, what does a pointcut do?

quick drill

Which advice type can run code both before and after a method and decide whether to call it?

quick drill

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, @Transactional included.

Practice — level up

0/1 solved

Write your answer, then compare it with a rubric and a model answer.

ExplainWhy was it not logged?

An @Around aspect times every method in the service package. The controller calls loanService.borrow(), which then calls this.sendReceipt() in the same class. Only borrow() shows up in the timing log. Explain why, and give one way to get sendReceipt() timed too.