AOP란?
코딩을 하다 보면 공통적으로 해야 하는 작업들이 있습니다. 대표적으로 로깅 (Logging)입니다. 프로그램에 문제가 생겼을 때 문제를 찾게 해 주는 단서가 로깅입니다. 그래서 당연히 중요한 것들을 최대한 자세히, 많이 남기는 게 좋습니다.
- 처음 요청이 시작할 때가 몇 시 몇 분이고 어떤 Payload가 담겨져서 왔는지,
- 중간중간 어떤 함수들을 호출했는지,
- 끝날 때는 몇 시 몇 분이고, 어떤 Response가 나갔는지
등등 다양합니다.
문제는 로깅 프레임워크나 라이브러리를 만들지 않는 이상 로깅은 애플리케이션의 핵심 기능이 전혀 아니라는 겁니다. 하지만 꼭 중요하고 필요한 것이기 때문에 빼먹을 수는 없습니다. 이걸 수기로 하게 되면 문제가 2가지 있습니다.
- 코드에 핵심 기능이 아닌 여러 부수 기능들을 위한 코드가 난잡하게 있게 됨
- 실수로 까먹을 수도 있음
이런 핵심 기능은 아닌데 여러 군데에서 공통적으로 필요한 기능을 공통의 관심사 (Cross-Cutting Concerns)라고 합니다. AOP (Aspect Oriented Programming)은 이런 공통의 관심사를 Aspect라는 추상화된 단위로 처리해 주는 기술입니다.
AOP 자체에 관한 용어들
Aspect | AOP에 필요한 여러 요소가 있는 class (Advice, Pointcut 등) | |
어드바이스 | Advice | 실제 AOP로 적용할 동작 |
포인트컷 | Pointcut | AOP를 어디에 적용할지 |
어드바이저 | Adviser | Pointcut + Advice, 스프링에서만 사용 |
위빙 | Weaving | AOP를 적용하는 과정, 크게 3가지 방식이 있음. (Compile-Time, Load-Time, Runtime) |
조인 포인트 | Join Point | AOP를 적용할 수 있는 모든 지점 |
🐜 위빙 (Weaving)
Advice 코드를 Pointcut에 따라 실제 코드에 삽입하는 과정을 위빙 (Weaving)이라고 합니다. 이때 위빙을 할 수 있는 지점이 3가지가 있는데요.
Compile-Time Weaving | Java를 컴파일해서 class가 되는데, 이때 class 파일 자체를 위빙 된 상태로 생성하는 방식 |
Load-Time Weaving | class 파일을 JVM에 로드해서 만들어진 Byte Code를 변경하는 방식 |
Runtime Weaving | class 정보나 Byte Code는 건들지 않고 Proxy 객체를 만드는 방식 |
각각의 방식 마다 장단점이 있습니다. 가장 큰 차이점은 Join Point가 달라집니다. 밑으로 갈수록 조인 포인트가 적어집니다. 예를 들어 Spring AOP에서 쓰는 Runtime Weaving은 Proxy 객체를 만드는 거 이외의 조작을 할 수 없기 때문에 Java 언어 자체의 기능만 사용할 수 있어 조인 포인트가 Method 밖에 없게 됩니다.
🐜 조인 포인트 (Join Point)
AOP에서 코드를 삽입할 수 있는 모든 지점을 조인 포인트 (Join Point)라고 합니다.
AOP 기술 관련 용어, Annotation 들
AspectJ | Java 환경에서 AOP를 지원하기 위한 기술입니다. Spring AOP에 비해서 훨씬 기능이 다양하지만 그만큼 사용하기 어렵고 잘 안 쓰는 기능도 많습니다. |
Spring AOP | Spring에서 제공하는 AOP 기술입니다. AspectJ와는 독립적이지만 AspectJ의 Annotation을 지원하긴 합니다. |
@Aspect | 특정 class를 Aspect으로 만드는 Annotation |
@Before @After @Around @AfterReturning @AfterThrowing |
Advice를 정의할 때 씀, 생명주기 어디에서 실행될 지에 관한 것 (전, 후, 예외 발생 등) |
Spring AOP 예시
@Retry를 붙이면 자동으로 재시도 해 주는 Annotation을 만들고 싶어 AOP를 적용한다고 해 보겠습니다.
@Aspect
public class RetryAspect {
@Around("@annotation(retry)")
public Object doRetry(ProceedingJoinPoint joinPoint, Retry retry) throws Throwable {
int maxRetry = retry.value();
Exception exceptionHolder = null;
for (int retryCount = 1; retryCount <= maxRetry; retryCount++) {
try {
return joinPoint.proceed(); // 로직 실행
} catch (Exception e) {
exceptionHolder = e;
}
}
throw exceptionHolder;
}
}
- @Aspect로 RetryAspect라는 class가 어드바이스와 포인트컷을 가지고 있는 AOP 객체라는 걸 가리키고 있습니다.
- @Around가 포인트컷을 지정하는 부분입니다. 여기서는 Retry라는 Annotation이 붙으면 적용하도록 하고 있습니다.
'👨💻 프로그래밍 > 📦 Backend' 카테고리의 다른 글
Gradle 기반 프로젝트에 Ktlint 적용하기 (3) | 2025.02.15 |
---|---|
@FunctionalInterface란? (1) | 2025.01.30 |
MDC로 풍부한 로그 쉽게 남기기 (0) | 2025.01.12 |
🥒 피클 (PKL): 새로운 설정 관리 언어 알아보기 (0) | 2024.11.02 |
Kotlin의 @JvmStatic 알아보기 (0) | 2024.08.12 |