AOP 포인트컷 - @target, @within

박찬우·2024년 2월 17일

스프링

목록 보기
70/88

@target, @within

  • @target
    • 실행 객체의 클래스에 주어진 타입의 애노테이션이 있는 조인 포인트
    • 인스턴스의 모든 메서드를 조인 포인트로 적용한다.
  • @within
    • 주어진 애노테이션이 있는 타입 내 조인 포인트
    • 해당 타입 내에 있는 메서드만 조인 포인트로 적용한다.
  • @target 은 부모 클래스의 메서드까지 어드바이스를 다 적용하고, @within 은 자기 자신의 클래스에 정의된 메서드에만 어드바이스를 적용
  • 주의
    • args , @args , @target 같은 포인트컷 지시자가 있으면 스
      프링은 모든 스프링 빈에 AOP를 적용하려고 시도한다
    • 이렇게 모든 스프링 빈에 AOP 프록시를 적용하려고 하면 스프링이 내부에서 사용하는 빈 중에는 final로 지정된 빈들도 있기 때문에 오류가 발생
    • 이러한 표현식은 최대한 프록시 적용 대상을 축소하는 표현식과 함께 사용해야 한다

예)

  • 애노테이션
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ClassAop {
}
  • 클래스
@ClassAop
@Component
public class MemberServiceImpl implements MemberService {
    @Override
    public String hello(String param) {
        return "ok";
    }

    public String internal(String param) {
        return "ok";
    }
}
  • test
@Slf4j
@Import({AtTargetAtWithinTest.Config.class})
@SpringBootTest
public class AtTargetAtWithinTest {
    @Autowired
    Child child;

    @Test
    void success() {
        log.info("child Proxy={}", child.getClass());
        child.childMethod(); //부모, 자식 모두 있는 메서드
        child.parentMethod(); //부모 클래스만 있는 메서드
    }

    static class Config {
        @Bean
        public Parent parent() {
            return new Parent();
        }
        @Bean
        public Child child() {
            return new Child();
        }
        @Bean
        public AtTargetAtWithinAspect atTargetAtWithinAspect() {
            return new AtTargetAtWithinAspect();
        }
    }

    static class Parent {
        public void parentMethod(){} //부모에만 있는 메서드
    }

    @ClassAop
    static class Child extends Parent {
        public void childMethod(){}
    }

    @Slf4j
    @Aspect
    static class AtTargetAtWithinAspect {
        //@target: 인스턴스 기준으로 모든 메서드의 조인 포인트를 선정, 부모 타입의 메서드도 적용
        @Around("execution(* hello.aop..*(..)) && @target(hello.aop.member.annotation.ClassAop)")
        public Object atTarget(ProceedingJoinPoint joinPoint) throws Throwable {
            log.info("[@target] {}", joinPoint.getSignature());
            return joinPoint.proceed();
        }

        //@within: 선택된 클래스 내부에 있는 메서드만 조인 포인트로 선정, 부모 타입의 메서드는 적용되지 않음
        @Around("execution(* hello.aop..*(..)) && @within(hello.aop.member.annotation.ClassAop)")
        public Object atWithin(ProceedingJoinPoint joinPoint) throws Throwable {
            log.info("[@within] {}", joinPoint.getSignature());
            return joinPoint.proceed();
        }
    }
}

profile
진짜 개발자가 되어보자

0개의 댓글