AOP means Aspect-Oriented Programming. It is useful when the same behavior must apply across many classes or methods, such as logging, auditing, timing, security-related checks or transaction infrastructure.
Many business methods
↓
same cross-cutting concern
↓
AOP
↓
one reusable aspect
| OOP | AOP |
|---|---|
| Main unit is class/object. | Main unit is aspect. |
| Focuses on business objects and responsibilities. | Focuses on behavior cutting across multiple objects. |
Example: OrderService. | Example: timing every service method. |
| Feature | Spring Boot behavior |
|---|---|
| AOP auto-configuration | Provided automatically. |
| Default proxy | CGLIB. |
| JDK proxy | Set spring.aop.proxy-target-class=false. |
| AspectJ on classpath | AspectJ auto-proxy support is automatically enabled. |
@EnableAspectJAutoProxy | Not required when Boot's AspectJ auto-configuration applies. |
spring.aop.proxy-target-class to false selects JDK proxies.A cross-cutting concern affects multiple unrelated parts of an application.
Without AOP, repeated infrastructure code can be placed inside every method. With AOP, the behavior can be defined once and applied through a pointcut.
| Term | Simple meaning |
|---|---|
| Aspect | Module containing a cross-cutting concern. |
| Join point | A point during execution where advice can apply. In Spring AOP, this represents method execution. |
| Advice | Action performed at a matched join point. |
| Pointcut | Rule that selects matching join points. |
| Target object | Object being advised. |
| AOP proxy | Proxy through which Spring applies advice. |
| Weaving | Connecting aspects with application behavior; Spring AOP uses runtime proxies. |
Caller ↓ Spring AOP proxy ↓ Advice ↓ Target method ↓ Advice / return ↓ Caller
Spring AOP is proxy-based. The proxy intercepts eligible calls and applies the configured advice around the target method.
Spring Boot's default AOP proxy strategy is CGLIB. This is class-based proxying and is useful when the target is a concrete class.
public class OrderService {
public void createOrder() {
// business logic
}
}
To use JDK dynamic proxies instead:
spring.aop.proxy-target-class=false
| Proxy | Boot setting | Simple idea |
|---|---|---|
| CGLIB | Default | Class-based proxying. |
| JDK dynamic proxy | false | Interface-based proxying. |
If AspectJ is on the classpath, Spring Boot's auto-configuration automatically enables AspectJ auto-proxy support. Therefore, you do not need to manually add:
@EnableAspectJAutoProxy
@EnableAspectJAutoProxy just because you are using Spring Boot. Boot can configure it automatically when AspectJ is present.import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service..*(..))")
public void beforeServiceMethod() {
System.out.println("Service method called");
}
}
| Code | Meaning |
|---|---|
@Aspect | Marks the class as an aspect. |
@Component | Registers it as a Spring bean. |
@Before | Runs before matching method execution. |
execution(...) | Pointcut selecting method executions. |
| Advice | When it runs | Typical use |
|---|---|---|
@Before | Before matched method. | Validation, logging. |
@AfterReturning | After normal completion. | Successful-result handling. |
@AfterThrowing | When an exception is thrown. | Error auditing. |
@After | After completion, success or failure. | Cleanup. |
@Around | Around execution. | Timing, wrapping, conditional execution. |
@Around when @Before or @AfterReturning is enough.@Before("execution(* com.example.service..*(..))")
public void before() {
System.out.println("Before service method");
}
Flow:
@Before → target method → return
@AfterReturning(
pointcut = "execution(* com.example.service..*(..))",
returning = "result"
)
public void afterReturning(Object result) {
System.out.println("Result = " + result);
}
This advice runs only after normal completion.
@AfterThrowing(
pointcut = "execution(* com.example.service..*(..))",
throwing = "ex"
)
public void afterThrowing(Exception ex) {
System.out.println("Failure: " + ex.getMessage());
}
This advice runs when a matched method exits by throwing an exception.
@After("execution(* com.example.service..*(..))")
public void after() {
System.out.println("Method finished");
}
Think of @After as finally-like behavior: it runs regardless of normal or exceptional completion.
@Around("execution(* com.example.service..*(..))")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
long start = System.currentTimeMillis();
Object result = joinPoint.proceed();
long time = System.currentTimeMillis() - start;
System.out.println("Execution time: " + time + " ms");
return result;
}
@Around starts
↓
before logic
↓
joinPoint.proceed()
↓
target method
↓
after logic
↓
return result
proceed() allows the underlying method to run. Forgetting it can prevent the target method from executing.A pointcut tells Spring which method executions should receive advice.
execution(* com.example.service..*(..))
Conceptually:
execution( any return type com.example.service package/subpackages any method any arguments )
Examples:
execution(* com.example.service.OrderService.createOrder(..)) execution(* com.example.service..*(..)) execution(public * com.example.service..*(..))
@Before("execution(* com.example.service..*(..))")
public void log() {
System.out.println("Service called");
}
The pointcut answers where. The advice method answers what.
@Aspect
@Component
public class PerformanceAspect {
@Around("execution(* com.example.service..*(..))")
public Object measure(ProceedingJoinPoint pjp) throws Throwable {
long start = System.nanoTime();
Object result = pjp.proceed();
long duration = System.nanoTime() - start;
System.out.println(
pjp.getSignature().getName()
+ " took " + duration + " ns"
);
return result;
}
}
One aspect can measure many service methods without putting timing code into each service.
@AfterReturning(
pointcut = "execution(* com.example.service.OrderService.create*(..))"
)
public void audit() {
System.out.println("Order operation completed");
}
This illustrates a cross-cutting audit concern. In production, use an appropriate audit/logging infrastructure rather than relying only on System.out.
@Before("execution(* com.example.admin..*(..))")
public void checkAccess() {
// check current user's permission
}
This demonstrates the AOP idea. For real authentication and authorization, Spring Security is generally the more appropriate dedicated solution.
| Spring AOP | AspectJ |
|---|---|
| Proxy-based. | Provides broader weaving capabilities. |
| Commonly targets Spring-managed method execution. | Can operate beyond the proxy-based model. |
| Simple Spring integration. | More powerful and more complex. |
Because Spring AOP is proxy-based, an internal call from one method to another method on the same target object can bypass the proxy.
class OrderService {
public void methodA() {
methodB(); // direct internal call
}
public void methodB() {
// advice may not run here
}
}
external caller
↓
Spring proxy
↓
methodA()
↓
this.methodB()
↓
target object directly
Transaction management is a classic cross-cutting concern.
@Transactional
public void placeOrder() {
// database operations
}
caller ↓ proxy ↓ begin transaction ↓ placeOrder() ↓ commit / rollback
This is the type of infrastructure behavior AOP helps apply declaratively around business operations.
| Use | Why AOP fits |
|---|---|
| Execution timing | Same behavior across many methods. |
| Audit logging | Cross-cutting and repetitive. |
| Transaction boundaries | Infrastructure around business operations. |
| Consistent diagnostics | Centralized behavior. |
spring.aop.proxy-target-class=true
This represents the default CGLIB/class-based strategy.
To use JDK proxies:
spring.aop.proxy-target-class=false
| Value | Meaning |
|---|---|
true | CGLIB/class-based proxying. |
false | JDK dynamic proxies. |
proceed(). The target may not execute.A way to modularize cross-cutting concerns such as logging, auditing and transactions.
Q2. What is Spring Boot's default AOP proxy?CGLIB.
Q3. How do you switch to JDK proxies?spring.aop.proxy-target-class=falseQ4. What is an aspect?
A module containing a cross-cutting concern.
Q5. What is a pointcut?A rule selecting join points where advice should run.
Q6. What is advice?The action executed at a matched join point.
Q7. What is an AOP proxy?The proxy through which Spring applies AOP behavior around a target bean.
Q8. Name the common advice types.Before, After Returning, After Throwing, After, and Around.
Q9. Why avoid unnecessary Around advice?It is the most powerful advice type and requires managing the continuation of the target invocation.
Q10. Why can self-invocation bypass AOP?The internal call can go directly to the target object instead of through the Spring proxy.
Q11. Is @EnableAspectJAutoProxy required in Spring Boot?Not when AspectJ is on the classpath and Boot's AOP auto-configuration applies.
@Aspect.@Before logging.@AfterReturning result logging.@AfterThrowing exception logging.@Around timing aspect.spring.aop.proxy-target-class=false and inspect behavior.| Concept | Remember |
|---|---|
| AOP | Cross-cutting concerns. |
| Aspect | The cross-cutting module. |
| Pointcut | WHERE. |
| Advice | WHAT action. |
| Join point | In Spring AOP, method execution. |
| Proxy | Spring interception mechanism. |
| Default | CGLIB. |
| JDK proxy | spring.aop.proxy-target-class=false. |
| Before | Before target. |
| After Returning | After normal completion. |
| After Throwing | When exception is thrown. |
| After | After completion. |
| Around | Wraps target execution. |
| AspectJ auto-proxy | Auto-enabled by Boot when AspectJ is on classpath. |
spring.aop.proxy-target-class=false for JDK proxies.@EnableAspectJAutoProxy is therefore not required in that situation.Aspect ↓ Pointcut = WHERE ↓ Advice = WHAT ↓ Spring Proxy ↓ Target Method