Tech/Spring

스프링 AOP - this VS target

봄의 개발자 2023. 10. 27.
728x90
반응형
  • this: 스프링 빈 객체(스프링 AOP 프록시)를 대상으로 하는 조인 포인트
  • target: Target 객체(스프링 AOP 프록시가 가르키는 실제 대상)를 대상으로 하는 조인 포인트
  • 둘 다 적용 타입 하나를 정확하게 지정해야 한다.
      • 같은 패턴 사용 불가
    • 부모 타입 허용

this vs target

  • 단순히 타입 하나를 정하면 되는데, this와 target은 어떤 차이가 있을까?

스프링에서 AOP 적용하면 실제 target 객체 대신 프록시 객체가 스프링 빈으로 등록된다.

  • this는 스프링 빈으로 등록되어있는 프록시 객체를 대상으로 포인트컷을 매칭한다.
  • target은 실제 target 객체를 대상으로 포인트컷을 매칭한다.
  • 프록시 생성 방식에 따른 차이
  • 스프링은 프록시를 생성할 때 JDK 동적 프록시와 CGLIB를 선택할 수 있다. 둘의 프록시를 생성하는 방식이 다르기 때문에 차이가 발생한다.

 

  • JDK 동적 프록시: 인터페이스가 필수이고, 인터페이스를 구현한 프록시 객체를 생성한다.
  • CGLIB: 인터페이스가 있어도 구체 클래스를 상속 받아서 프록시 객체를 생성한다.

JDK 동적 프록시: this vs target

  • MemberService 인터페이스 지정
    • this(hello.aop.member.MemberService)
      • proxy 객체를 보고 판단한다.
      • this는 부모 타입을 허용하기 때문에 AOP가 적용된다.
    • target(hello.aop.member.MemberService)
      • target 객체를 보고 판단한다.
      • target은 부모 타입을 허용하기 때문에 AOP가 적용된다.
  • MemberServiceImpl 구체 클래스 지정
    • this(hello.aop.member.MemberServiceImpl)
      • proxy 객체를 보고 판단한다.
      • JDK 동적 프록시로 만들어진 proxy 객체는 MemberService 인터페이스를 기반으로 구현된 새로운 클래스이다.
      • 따라서 MEmberServiceImple을 전혀 알지 못하므로 AOP 적용 대상이 아니다.-
    • target(hello.aop.member.MemberServiceImpl)
      • target 객체를 보고 판단한다.
      • target 객체가 MemberServiceImpl 타입이므로 AOP 적용 대상이다.

CGLIB 프록시

  • MemberService 인터페이스 지정
    • this(hello.aop.member.MemberService)
      • proxy 객체를 보고 판단한다.
      • this는 부모 타입을 허용하기 때문에 AOP가 적용된다.
    • target(hello.aop.member.MemberService)
      • target 객체를 보고 판단한다.
      • target은 부모 타입을 허용하기 때문에 AOP가 적용된다.
  • MemberServiceImpl 구체 클래스 지정
    • this(hello.aop.member.MemberServiceImpl)
      • proxy 객체를 보고 판단한다.
      • CGLIB로 만들어진 proxy객체는 MemberServiceImpl를 상속 받아서 만들었기 때문에 AOP가 적용된다.
      • this가 부모 타입을 허용하기 때문에 포인트컷의 대상이 된다.
    • target(hello.aop.member.MemberServiceImpl)
      • target 객체를 보고 판단한다.
      • target 객체가 MemberServiceImpl 타입이므로 AOP 적용 대상이다.
// 부모 타입 허용
@Around("this(hello.aop.member.MemberService)")
public Object doThisInterface(ProceedingJoinPoint joinPoint) throws Throwable {
	log.info("[this-interface] {}", joinPoint.getSignature());
	return joinPoint.proceed();
}

 

@Around("target(hello.aop.member.MemberService)")
public Object doTargetInterface(ProceedingJoinPoint joinPoint) throws Throwable {
	log.info("[target-interface] {}", joinPoint.getSignature());
	return joinPoint.proceed();
}

 

@Around("this(hello.aop.member.MemberServiceImpl)")
public Object doThis(ProceedingJoinPoint joinPoint) throws Throwable {
	log.info("[this-impl] {}", joinPoint.getSignature());
	return joinPoint.proceed();
}

 

@Around("target(hello.aop.member.MemberServiceImpl)")
public Object doTarget(ProceedingJoinPoint joinPoint) throws Throwable {
	log.info("[target-impl] {}", joinPoint.getSignature());
	return joinPoint.proceed();
}

 

spring.aop.proxy-target-class=true //CGLIB

혹은

@SpringBootTest(properties = "spring.aop.propxy-target-class=false")

 

JDK 동적 프록시를 사용하는 경우

스프링 AOP - this VS target - undefined - JDK 동적 프록시를 사용하는 경우

  • target-imple은 memberServiceImple은 뭔지 전혀 모르기 때문에 (memberServiceImpl이 부모 타입도 아니고) 프록시에 어드바이스 적용이 안되는 것임

CGLIB를 사용하는 경우

스프링 AOP - this VS target - undefined - 모든 영역

  • this-imple 까지 됨
  • CGLIB 프록시가 memberServiceImpl을 상속받아서 만든 것이기 때문에 구체 클래스를 딱 지정해도 부모 타입이기 때문에 어드바이스 적용이 됨
  • 스프링부트는 기본적으로 CGLIB 사용

 

💡 this , target 지시자는 단독으로 사용되기 보다는 파라미터 바인딩에서 주로 사용된다.
728x90
반응형

댓글