
목차
- [Spring AOP] 포인트컷 표현식 - this, target
- [Spring AOP] 포인트컷 표현식 - Advice 에 매게변수 전달
- [Spring AOP] 포인트컷 표현식 - bean
- [Spring AOP] 포인트컷 표현식 - @args
- [Spring AOP] 포인트컷 표현식 - @annotation
- [Spring AOP] 포인트컷 표현식 - @target, @within
- [Spring AOP] 포인트컷 표현식 - args
- [Spring AOP] 포인트컷 표현식 - within
- [Spring AOP] 포인트컷 표현식 - execution
- [Spring AOP] 포인트컷
@annotation 포인트컷
메서드가 주어진 어노테이션을 가지고 있는 조인 포인트를 매칭
@annotation 은 특정 어노테이션이 적용된 메소드 를 기준으로 Advice 를 적용할때 사용하는 표현식입니다.
위와 같이 @annotation 에서 정의된 어노테이션에 Advice 를 적용합니다.
@annotation 포인트컷 사용하기
1. Custom Annotation 생성
AOP 에서 사용할 커스텀 어노테이션을 정의합니다. 이때 두 가지 메타 어노테이션을 반드시 지정해야 합니다.
|
@Target(ElementType.METHOD): 이 어노테이션이 메소드에만 선언될 수 있도록 제한합니다.@annotation포인트컷은 메소드 단위로 동작하므로 반드시METHOD로 지정해야 합니다.@Retention(RetentionPolicy.RUNTIME): 어노테이션 정보를 런타임 시점까지 유지합니다. Spring AOP 는 런타임에 프록시를 통해 어노테이션 존재 여부를 확인하므로,RUNTIME으로 설정하지 않으면 AOP 가 동작하지 않습니다. (CLASS나SOURCE로 설정하면 런타임에 어노테이션 정보가 사라짐)
2. Advisor 생성
어노테이션을 이용해 Advice 를 적용하기 위해 @annotation 에 어노테이션의 완전한 패키지 경로(FQCN) 를 지정합니다.
|
3. Custom Annotation 적용
@MethodAop 를 메소드에 적용합니다. 해당 어노테이션이 적용된 메소드에 Advice 를 적용합니다.
|
MemberService 객체가 프록시 객체로 생성된 것을 확인할 수 있습니다. 또한, @MethodAop 가 적용된 hello 메소드에 Advice 로직이 수행된 것을 확인할 수 있습니다.
|
2021-12-21 00:06:40.720 INFO 35688 --- [ Test worker] c.example.aop.pointcut.AtAnnotationTest : memberService Proxy = class com.example.aop.member.MemberServiceImpl$$EnhancerBySpringCGLIB$$a8e51818 |
어노테이션 파라미터 바인딩
앞선 예제에서는 포인트컷에 어노테이션의 패키지 경로를 직접 문자열로 지정했습니다. 이 방식은 어노테이션이 적용된 메소드에 Advice 를 실행할 수는 있지만, Advice 내부에서 어노테이션에 담긴 값(예: @MethodAop("test") 의 "test")에는 접근할 수 없습니다.
Advice 메소드의 파라미터에 어노테이션 객체를 직접 바인딩하면, 어노테이션에 설정된 값을 Advice 내부에서 활용할 수 있습니다.
@annotation(어노테이션변수명) 형태로 포인트컷을 지정하고, Advice 메소드 파라미터에 동일한 이름과 어노테이션 타입으로 선언하면 Spring 이 자동으로 해당 어노테이션 인스턴스를 주입해 줍니다.
|
@MethodAop("test") 와 같이 어노테이션에 지정한 값이 methodAop.value() 를 통해 그대로 전달됩니다.
[@annotation] String com.example.aop.member.MemberServiceImpl.hello(String), value=test |
@annotation vs @within
@annotation 과 @within 은 둘 다 어노테이션을 기반으로 포인트컷을 지정하지만, 어노테이션을 어디에 선언하느냐에 따라 동작 방식이 다릅니다.
| 표현식 | 어노테이션 적용 위치 | 매칭 범위 |
|---|---|---|
@annotation |
메소드 에 선언 | 해당 어노테이션이 붙은 메소드만 매칭 |
@within |
클래스(타입) 에 선언 | 해당 어노테이션이 붙은 클래스의 모든 메소드 매칭 |
@within - 클래스에 선언
// @within 예시 - 클래스에 어노테이션을 선언 |
@annotation - 메소드에 선언
// @annotation 예시 - 메소드에 어노테이션을 선언 |
선택 기준:
- 클래스 내 모든 메소드에 동일한 부가 기능이 필요하다면 →
@within(예: 특정 레이어 전체에 트랜잭션, 로깅 적용) - 특정 메소드에만 선택적으로 부가 기능이 필요하다면 →
@annotation(예: 일부 API 에만 실행 시간 측정, 권한 체크 적용)
실무 활용 예시
@annotation 은 특정 메소드에만 선택적으로 부가 기능을 적용할 때 유용합니다. 비즈니스 로직은 그대로 두고 어노테이션 선언만으로 원하는 메소드에 부가 기능을 붙일 수 있어, 관심사 분리가 명확해집니다.
커스텀 로깅
value() 속성에 메소드 설명 문자열을 받아, Advice 에서 로그 메시지로 활용합니다.
|
|
@Loggable("주문 생성") 처럼 어노테이션에 전달한 문자열이 loggable.value() 로 바인딩되어 로그에 출력됩니다. 메소드마다 다른 설명을 로그로 남길 수 있고, OrderService 코드에는 로깅 관련 코드가 전혀 없어도 됩니다.
|
실행 시간 측정
성능이 중요한 메소드에만 선택적으로 실행 시간을 측정하고 싶을 때 활용합니다. System.currentTimeMillis() 로 메소드 실행 전후 시간을 기록하고, finally 블록에서 차이를 계산해 로그로 출력합니다.
|
|
finally 블록을 사용하면 메소드에서 예외가 발생하더라도 실행 시간이 반드시 측정됩니다. 측정이 필요한 메소드에 @TraceTime 어노테이션만 붙이면 되므로, 비즈니스 로직에 측정 코드를 직접 삽입할 필요가 없습니다.
이처럼 @annotation 을 활용하면 코드 변경 없이 어노테이션 선언만으로 부가 기능을 메소드 단위로 유연하게 적용할 수 있습니다.