Spring AOP Interview Questions and Answers

Spring AOP interview questions with tested advice, pointcut and proxy examples. See why self-invocation bypasses advice and when to use each advice type.

Spring tutorials

Spring AOP adds behavior such as timing, logging, or access checks around method calls to Spring-managed beans. It does this through a proxy that intercepts a call before passing it to the target object. The most useful interview answer includes that boundary, because it explains both when advice runs and why a call within the same object can bypass it.

1. What Does Spring AOP Do?

Consider an order service that places orders. Measuring how long each call takes is useful, but the timing code does not belong to the order placement rule. Timing is a cross-cutting concern because the same behavior may apply to many service methods.

An aspect holds that shared behavior and selects where to apply it. The service keeps its business method, while Spring routes matching calls through a proxy that runs the timing code. Spring AOP works at the execution of methods on Spring-managed beans. It does not intercept arbitrary object creation or field access.

The call path keeps the timing concern outside the order method.

A caller reaches a Spring proxy, which applies timing advice before invoking the order service method.

2. What Are an Aspect, a Join Point, a Pointcut and Advice?

The terms describe different parts of one call. A join point in Spring AOP is a method execution that can be advised. A pointcut is an expression that selects join points. Advice is the action performed when a selected call reaches the proxy. The aspect groups the pointcut and advice. The target is the object whose method ultimately runs.

The pointcut in the working example selects executions of OrderService.place(..).

@Around("execution(* com.howtodoinjava.aop.OrderService.place(..))")

Here, @Around identifies the advice type and the execution expression is the pointcut. When another bean calls place() through its Spring proxy, the advice runs before and after the target method. The complete aspect appears with the application code below.

3. What Are the Five Types of Advice?

Choose the advice type according to the behavior needed. A log before a call does not need control over the method’s return value, while a timer needs to measure both before and after execution.

AdviceWhen it runsTypical use
@BeforeBefore the target methodRecord an attempted operation
@AfterReturningAfter a normal returnInspect a successful result
@AfterThrowingAfter an exceptionRecord a failed operation
@AfterAfter the method finishes, including exceptional completionRelease or report after a call
@AroundAround the invocationMeasure duration or decide whether to proceed

@Around advice receives a ProceedingJoinPoint. Calling proceed() continues the invocation and returns its result. If the advice does not call proceed(), the target method does not run. That power is useful for timing, but simpler advice is easier to use when only one side of the call matters.

The diagram places each advice type relative to the target method. An exception follows the throwing branch instead of the normal-return branch.

Advice timing around a target method. Before runs on entry, AfterReturning on normal return, AfterThrowing on exception, After on either exit, and Around spans the invocation.

4. How Do We Measure a Method Call with Spring AOP?

The following small application places an order and measures its place() call. Add spring-boot-starter-aspectj to the Maven project. Spring Boot configures Spring AOP when AspectJ is on the classpath, so this example needs no explicit @EnableAspectJAutoProxy annotation.

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aspectj</artifactId>
</dependency>

The service has one business method and a batch method that calls it. The internal call will help expose the proxy boundary after the normal call works.

package com.howtodoinjava.aop;

import org.springframework.stereotype.Service;

@Service
public class OrderService {
    public String place(String id) {
        return "placed " + id;
    }

    public String placeBatch(String id) {
        return place(id);
    }
}

The aspect measures elapsed time around place(). Its finally block records a completed timing attempt even if the method throws. It returns the original result from proceed() without changing the service’s behavior.

package com.howtodoinjava.aop;

import java.util.concurrent.atomic.AtomicInteger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class TimingAspect {
    private final AtomicInteger timedCalls = new AtomicInteger();
    private volatile long lastDurationNanos = -1;

    @Around("execution(* com.howtodoinjava.aop.OrderService.place(..))")
    public Object timePlace(ProceedingJoinPoint call) throws Throwable {
        long started = System.nanoTime();
        try {
            return call.proceed();
        } finally {
            lastDurationNanos = System.nanoTime() - started;
            timedCalls.incrementAndGet();
        }
    }

    public int timedCalls() { return timedCalls.get(); }
    public long lastDurationNanos() { return lastDurationNanos; }
}

In the execution expression, * accepts any return type, the fully qualified name selects OrderService.place, and (..) accepts any argument list. The expression selects executions of place(); it does not select placeBatch().

The application asks Spring for the service and aspect, makes two calls, and prints what the aspect observed.

package com.howtodoinjava.aop;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.CommandLineRunner;
import org.springframework.context.annotation.Bean;

@SpringBootApplication
public class AopInterviewApplication {
    public static void main(String[] args) {
        SpringApplication.run(AopInterviewApplication.class, args);
    }

    @Bean
    CommandLineRunner run(OrderService orders, TimingAspect timing) {
        return args -> {
            System.out.println(orders.place("A-1"));
            System.out.println(orders.placeBatch("B-1"));
            System.out.println("timed calls " + timing.timedCalls());
            System.out.println("duration recorded " + (timing.lastDurationNanos() >= 0));
        };
    }
}

Running the application prints the following lines after Spring startup. The duration itself varies, so the example checks that the aspect recorded one.

placed A-1
placed B-1
timed calls 1
duration recorded true

Both orders were placed, but the aspect counted only one call. The next section explains why the batch call did not add a second timing record.

5. Why Does Self-Invocation Bypass the Advice?

The runner calls orders.place(“A-1”) through the injected Spring proxy. The pointcut matches, so timePlace() runs once. The runner then calls orders.placeBatch(“B-1”). That method reaches the target object, where its call to place(id) stays within the same object. The internal call does not go back through the proxy, so the timing advice does not run again.

External calls pass through the Spring proxy and timing advice before reaching the order service. An internal call from placeBatch to place stays within the target and bypasses the proxy.

This is self-invocation, and it is a common reason an aspect appears to work for one call but not another. The Spring proxying reference documents this boundary. If the batch path must time each order placement, move the advised operation to a separate Spring bean and call that bean from the batch service. The call then crosses the proxy boundary.

6. Which Methods Can a Spring AOP Proxy Advise?

Spring AOP can use a JDK dynamic proxy for an interface or a class-based proxy for the target class. Spring Boot uses class-based proxies by default. Setting spring.aop.proxy-target-class=false requests interface-based proxies when an interface is available. The proxy choice changes what type callers can use, but it does not remove the self-invocation rule.

The proxy must expose a method that a caller can reach. This diagram shows the two proxy choices and the methods that remain outside the class-based proxy’s advice boundary.

A JDK proxy exposes interface methods. A class-based proxy can advise overridable methods on a Spring bean, but cannot advise private or final methods.

A method must be reachable through the proxy to be advised. Private methods cannot be advised by Spring AOP, and final methods cannot be overridden by a class-based proxy. In addition, constructing an object directly with new leaves it outside Spring’s bean and proxy lifecycle. For a missing advice call, first check that Spring created the target bean, the pointcut matches its method, and the caller invokes it through the proxy.

7. How Does Spring AOP Differ from AspectJ Weaving?

Spring AOP is a good fit for behavior around Spring bean methods. AspectJ weaving can advise a wider range of join points, including constructors and field access. The two tools therefore have different boundaries. Adding AspectJ annotations to a Spring AOP aspect does not make a private method or an internal self-call pass through a Spring proxy.

The difference is the set of join points available for advice.

Spring AOP advises method executions on Spring-managed beans through proxies. AspectJ weaving can also advise constructors and field access.

8. What Happens When Multiple Aspects Advise the Same Method?

When several aspects advise the same method, use @Order if their sequence affects behavior. The aspect with the lower order value runs first on entry and last on exit. Two aspects with the same order value have no guaranteed relative order, so dependent behavior should use distinct values. For independent logging and timing, avoid relying on an incidental order.

With order values 1 and 2, the advice nests around the target call as shown below. The method returns through the aspects in reverse order.

Aspect with order 1 enters, aspect with order 2 enters, the target method runs, then aspect 2 and aspect 1 exit.

Happy Learning!

Leave a Comment

Comments are closed.

About Us

HowToDoInJava provides tutorials and how-to guides on Java and related technologies.

It also shares the best practices, algorithms & solutions and frequently asked interview questions.