코딩/sparta TIL

TIL 38 : AOP

americanoallday 2025. 4. 24. 14:01

💡 Spring AOP는 “포인트컷 표현식”이 해당 Advice 메서드에만 매핑된다?

@Before("@annotation(com.example.CheckSomething) && args(email)")
public void checkSomething(String email) { ... }

이렇게 포인트컷을 작성하면, Spring은 이 포인트컷을 이 Advice 메서드 하나에만 적용.

 

✅ 포인트컷(Pointcut) 이란?

AOP에서 “어떤 메서드에 Advice(전처리, 후처리 등)를 적용할지 지정하는 조건”
@Before("@annotation(CheckUserDeleted) && args(email)")
public void checkUserDeleted(String email) { ... }

🧠 “CheckUserDeleted 어노테이션이 붙고, 첫 번째 인자가 email인 메서드에 checkUserDeleted() 메서드를 실행 전에 자동으로 적용하라는 뜻!”

 

❗그런데 문제는?

Spring AOP는 미리 컴파일 타임에 “이 Advice가 어디에 적용될지” 검사

  • args(email) 이라는 조건은:
    • “어노테이션이 붙었고, 첫 번째 인자가 email인 메서드”를 찾겠다는 뜻
  • 그런데 그런 메서드가 코드에 없으면?
    • “적용할 메서드가 없네? → 이 Advice 쓸모없음” → 경고

 

📘 그래서 말한 뜻 다시 해석

하나의 포인트컷 표현식은그 포인트컷 조건에 맞는 Advice 메서드에만 적용되기 때문에 조건을 만족하는 메서드가 없으면 경고가 뜸

 

 

그럼 왜  args(email), args(userId) 등으로 Advice를 여러 개 만들면 IntelliJ가 경고를 줄까?

🔥 진짜 핵심 포인트!

Spring AOP는 포인트컷 조건 하나하나가 적용될 메서드가 반드시 실제로 있어야 함.

Spring AOP는 args(...)에서 매개변수 순서, 개수, 이름까지 엄격하게 따짐!

 

🧨 실제 서비스 메서드 시그니처:

→ 이건 인자가 2개임!

public void deleteUser(Long userId, String password)

 

 

근데 AOP Advice는:

@Before("@annotation(CheckUserDeleted) && args(userId)")
public void checkUserDeletedById(Long userId)

→ 이건 “인자가 딱 하나”일 때만 매칭!

❗ 그래서 이 포인트컷은 args(userId)만 있을 때만 동작하고, args(userId, password) 같은 메서드는 매칭이 안 돼버려서 경고가 뜬 것

 

 

예시 상황 정리

@Before("@annotation(CheckUserDeleted) && args(email)")
public void checkEmail(String email) { ... }

@Before("@annotation(CheckUserDeleted) && args(userId)")
public void checkId(Long userId) { ... }

@Before("@annotation(CheckUserDeleted) && args(requestDto)")
public void checkDto(SignUpRequestDto requestDto) { ... }

 

 

😵 그런데 현재 프로젝트에 이런 메서드가 없다면?

@CheckUserDeleted
public void someMethod(Double money)  // ❌ 조건 불일치

 

 

해결 방법 

✅ Advice 통합 (추천)

args(arg,..)로 받고 instanceof로 분기

@Before("@annotation(com.example.yamyam16.auth.common.annotation.CheckUserDeleted) && args(arg,..)")
    public void checkUserDeleted(Object arg) {
        if (arg instanceof String email) {
            checkDeletedByEmail(email);
        } else if (arg instanceof Long userId) {
            checkDeletedByUserId(userId);
        } else if (arg instanceof SignUpRequestDto dto) {
            checkDeletedByEmail(dto.getEmail());
        } else if (arg instanceof LoginRequestDto dto) {
            checkDeletedByEmail(dto.getEmail());
        }
    }