Spring AOP (Aspect-Oriented Programming)
AOP = separating cross-cutting concerns from business logic.
Cross-cutting concerns = logic used in many places:
- logging
- transactions
- security
- performance monitoring
class Service {
public void process() {
System.out.println("Start log");
System.out.println("End log");
}
}
Logging is mixed with business logic.
With AOP
class Service {
public void process() {
}
}
Real-life analogy
Imagine that you go to a bank.
1. You enter
2. Security check happens
3. You do your transaction
4. Logging happens
You ony care about transaction.
But security + logging happen automatically.
class BankService {
public void transferMoney() {
System.out.println("Transferring money...");
}
}
No logging here, no security here.
They will go into an aspect.
Minimal Example
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.24</version>
</dependency>
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.1.1</version>
</dependency>
</dependencies>
package com.example.demo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.stereotype.Component;
import org.aspectj.lang.annotation.*;
public class Main {
public static void main(String[] args) {
ApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);
BankService service = context.getBean(BankService.class);
service.transferMoney();
}
}
@Configuration
@ComponentScan("com.example")
@EnableAspectJAutoProxy
class AppConfig {
}
@Component
class BankService {
public void transferMoney() {
System.out.println("Transferring money...");
}
}
@Aspect
@Component
class LoggingAspect {
@Before("execution(* BankService.transferMoney(..))")
public void before() {
System.out.println(">> Security check");
}
@After("execution(* BankService.transferMoney(..))")
public void after() {
System.out.println(">> Logging after method");
}
}
The magic (simplified)
Spring does NOT modify your class.
Spring creates a proxy object.
Proxy intercepts method calls.
Executes aspect logic.
BankService service;
ProxyBankService proxy;
proxy.transferMoney();
before();
realService.transferMoney();
after();