Spring AOP 멀티모듈 이슈
안녕하세요, 이번 포스팅에서는 Spring AOP를 멀티모듈 환경에서 사용하면서 겪은 문제와 그 해결 방법을 공유하려고 합니다. 멀티모듈에서 공통 기능을 분리해 사용하는 분들께 도움이 되기를 바랍니다.
문제 상황: 멀티모듈에서 애노테이션 추출 문제
Spring AOP를 활용해 특정 메서드 실행 후 이벤트를 발생시키는 기능을 구현하면서 문제가 발생했습니다. 공통 모듈에 정의한 애노테이션을 API 모듈에서 사용하고 있었고 다음과 같이 AOP를 적용했을 때 오류가 발생했습니다
@Aspect
@Component
public class CommentNotificationAspect {
@AfterReturning(value = "@annotation(commentNotification)")
public void afterScrapNotification(JoinPoint joinPoint, SendCommentNotification commentNotification) {
// 로직 처리
}
}
여기서 @SendCommentNotification
애노테이션은 common
모듈에 정의되어 있었고 api
모듈에서 이를 사용하는 구조였습니다. 그러나 아래와 같은 오류가 발생했습니다.
오류 로그
java.lang.IllegalStateException: Required to bind 2 arguments, but only bound 1 (JoinPointMatch was NOT bound in invocation)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.argBinding(AbstractAspectJAdvice.java:601)
at org.springframework.aop.aspectj.AbstractAspectJAdvice.invokeAdviceMethod(AbstractAspectJAdvice.java:627)
이 오류는 Spring이 애노테이션을 인자로 받아야 할 때 바인딩 문제로 인해 발생한 것입니다. 특히 멀티모듈 환경에서는 애노테이션을 매개변수로 직접 받으려 할 때 모듈 간 참조 문제로 인해 이런 오류가 생길 수 있습니다.
문제 해결: 리플렉션을 사용한 애노테이션 추출
해결 방법은 애노테이션을 리플렉션을 통해 직접 추출하는 것이었습니다.
AOP 메서드에서 애노테이션을 직접 인자로 받지 않고, 메서드 정보를 리플렉션으로 조회해 애노테이션을 가져오도록 수정했습니다.
수정된 코드는 다음과 같습니다
@Aspect
@Component
public class CommentNotificationAspect {
@AfterReturning(value = "@annotation(com.common.annotation.SendCommentNotification)")
public void afterScrapNotification(JoinPoint joinPoint) {
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
Method method = signature.getMethod();
SendCommentNotification commentNotification = method.getAnnotation(SendCommentNotification.class);
Optional<Comment> commentOptional = Arrays.stream(joinPoint.getArgs())
.filter(Comment.class::isInstance)
.map(Comment.class::cast)
.findFirst();
Long fromMemberId = SecurityUtil.getCurrentMember().getId();
commentOptional.ifPresent(comment -> {
NotiCategory notiCategory = commentNotification.notiCategory();
log.info("[Notification] {} - Notification Type: {}", joinPoint.getSignature(), notiCategory);
Events.raise(new CommentEvent(comment, notiCategory, fromMemberId));
});
}
}
코드 설명
- MethodSignature 사용:
MethodSignature
를 통해 메서드 정보를 가져옵니다. - 리플렉션을 통한 애노테이션 추출:
method.getAnnotation(SendCommentNotification.class)
를 사용하여 애노테이션을 추출합니다. 이를 통해 애노테이션 정보를 안전하게 사용할 수 있었습니다.
이렇게 수정한 후 오류가 더 이상 발생하지 않았고 애노테이션 정보를 안정적으로 사용할 수 있었습니다.
교훈과 결론
멀티모듈 환경에서 AOP와 애노테이션을 사용할 때 주의해야 할 점은 다음과 같습니다:
- 애노테이션 추출 방식: 멀티모듈 환경에서는 애노테이션을 직접 매개변수로 받기보다 리플렉션으로 추출하는 것이 더 안정적입니다.
- AOP와 모듈 간 의존성: 모듈 간의 의존성이 복잡해질수록 AOP 적용 방식에도 신중을 기해야 합니다. 애노테이션이 다른 모듈에 정의된 경우 리플렉션을 사용해 참조하는 것이 좋습니다.
'프로젝트 > 똑립' 카테고리의 다른 글
똑립 3. 멀티쓰레드 환경에서 동시성 제어. 분산락 적용 (0) | 2024.09.08 |
---|---|
똑립 2. REQUIRES_NEW / TransactionalEventListener + Async 알림 문제 복기 (1) | 2024.09.04 |
똑립 1. 알림기능, 문제의 시작 (0) | 2024.04.20 |