[Spring Framework] AOP
🧩 AOP란 무엇인가?
AOP(Aspect-Oriented Programming)는 객체 지향 프로그래밍의 한계를 보완하는 프로그래밍 패러다임이다. AOP는 애플리케이션 전반에 걸쳐 중복적으로 사용되는 공통 관심사(cross-cutting concerns)를 모듈화하여 코드의 재사용성과 유지보수성을 높이는 데 중점을 둔다. 공통 관심사의 예시에는 로깅, 트랜잭션 관리, 보안, 캐싱, 오류 처리 등이 있다.
🔑 AOP의 주요 개념
🎯 포인트컷 (Pointcut)
포인트컷(Pointcut)은 어드바이스를 적용할 조인 포인트(Join Point)를 선택하는 표현식이다. 조인 포인트는 메서드 실행, 객체 생성, 필드 접근 등 다양한 애플리케이션 실행 지점을 나타낸다.
예시:
1
2
@Pointcut("execution(* com.example.service.*.*(..))")
public void serviceLayer() {}
이 포인트컷은 com.example.service 패키지의 모든 클래스의 모든 메서드를 대상으로 지정한다.
📊 포인트컷 표현식
execution(): 메서드 실행 조인 포인트를 매칭within(): 특정 타입 내의 조인 포인트를 매칭this(): 프록시 객체를 대상으로 하는 조인 포인트를 매칭target(): 대상 객체를 대상으로 하는 조인 포인트를 매칭args(): 메서드의 인자를 대상으로 하는 조인 포인트를 매칭
💡 어드바이스 (Advice)
어드바이스(Advice)는 AOP에서 “무엇을” 할 것인지를 정의하는 부분이다. 즉, 횡단 관심사(cross-cutting concern)의 구현체라고 할 수 있다. 어드바이스는 특정 조인 포인트에서 실행될 실제 로직을 포함하고 있다.
📚 어드바이스 유형
⏮️ Before
- 조인 포인트 실행 전에 실행된다.
- 예: 메소드 실행 전 로깅, 파라미터 유효성 검사
1 2 3 4
@Before("execution(* com.example.service.*.*(..))") public void logBefore(JoinPoint joinPoint) { System.out.println("Before method: " + joinPoint.getSignature().getName()); }
⏭️ After
- 조인 포인트 실행 후 항상 실행된다.(정상 종료, 예외 발생 모두 포함)
- 예: 리소스 정리, 통계 업데이트
1 2 3 4
@After("execution(* com.example.service.*.*(..))") public void logAfter(JoinPoint joinPoint) { System.out.println("After method: " + joinPoint.getSignature().getName()); }
✅ AfterReturning
- 조인 포인트가 정상적으로 종료된 후 실행된다.
- 예: 반환값 로깅, 추가 결과 처리
1 2 3 4
@AfterReturning(pointcut = "execution(* com.example.service.*.*(..))", returning = "result") public void logAfterReturning(JoinPoint joinPoint, Object result) { System.out.println("Method returned: " + result); }
❌ AfterThrowing
- 조인 포인트에서 예외가 발생했을 때 실행된다.
- 예: 예외 로깅, 추가적인 예외 처리
1 2 3 4
@AfterThrowing(pointcut = "execution(* com.example.service.*.*(..))", throwing = "error") public void logAfterThrowing(JoinPoint joinPoint, Throwable error) { System.out.println("Exception in " + joinPoint.getSignature().getName() + ": " + error); }
🔄 Around
- 가장 강력한 어드바이스로, 조인 포인트 실행 전후에 로직을 실행할 수 있다.
- 조인 포인트 실행 여부를 직접 제어할 수 있다.
- 예: 메소드 실행 시간 측정, 트랜잭션 관리
1 2 3 4 5 6 7 8 9 10 11
@Around("execution(* com.example.service.*.*(..))") public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable { long start = System.currentTimeMillis(); Object result = joinPoint.proceed(); // 실제 메소드 실행 long executionTime = System.currentTimeMillis() - start; System.out.println(joinPoint.getSignature() + " executed in " + executionTime + "ms"); return result; }
🔗 어드바이저 (Advisor)
어드바이저(Advisor)는 포인트컷과 어드바이스를 결합하여 특정 상황에서 특정 동작을 수행하도록 한다. Spring AOP에서는 @Aspect 어노테이션을 사용해 어드바이저를 정의한다.
예시:
1
2
3
4
5
6
7
8
9
@Aspect
@Component
public class LoggingAspect {
@Before("execution(* com.example.service.*.*(..))")
public void logMethodEntry(JoinPoint joinPoint) {
String methodName = joinPoint.getSignature().getName();
System.out.println("Entering method: " + methodName);
}
}
💻 실제 사용 예시
트랜잭션 관리를 AOP로 구현한 예시:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Aspect
@Component
public class TransactionAspect {
@Autowired
private PlatformTransactionManager transactionManager;
@Around("@annotation(Transactional)")
public Object manageTransaction(ProceedingJoinPoint joinPoint) throws Throwable {
TransactionStatus status = transactionManager.getTransaction(new DefaultTransactionDefinition());
try {
Object result = joinPoint.proceed();
transactionManager.commit(status);
return result;
} catch (Exception e) {
transactionManager.rollback(status);
throw e;
}
}
}
이 예시에서는 @Transactional 어노테이션이 붙은 메서드에 대해 트랜잭션을 자동으로 관리한다.
Leave a comment