You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
스프링에서 AOP를 적용하면 실제 target 객체 대신에 프록시 객체가 스프링 빈으로 등록된다.
this는 스프링 빈으로 등록되어 있는 프록시 객체를 대상으로 포인트컷을 매칭한다.
target은 실제 target 객체를 대상으로 포인트컷을 매칭한다.
✅ 프록시 생성 방식에 따른 차이
스프링은 프록시를 생성할 때 JDK 동적 프록시와 CGLIB를 선택할 수 있다. 둘의 프록시를 생성하는 방식이 다르기 때문에 차이가 발생한다.
JDK 동적 프록시 : 인터페이스가 필수이고, 인터페이스를 구현한 프록시 객체를 생성한다.
CGLIB: 인터페이스가 있어도 구체 클래스를 상속 받아서 프록시 객체를 생성한다.
먼저 JDK 동적 프록시를 적용했을 때 this, target을 알아보자.
✅ MemberService 인터페이스 지정
this(hello.aop.member.MemberService)
proxy 객체를 보고 판단한다.this는 부모 타입을 허용하기 때문에 AOP가 적용된다.
target(hello.aop.member.MemberService)
target 객체를 보고 판단한다. target은 부모 타입을 허용하기 때문에 AOP가 적용된다.
✅ MembmerServiceImpl 구체 클래스 지정
this(hello.aop.member.MemberServiceImpl) : proxy 객체를 보고 판단한다.
JDK 동적 프록시로 만들어진 proxy 객체는 MemberService 인터페이스를 기반으로 구현된 새로운 클래스다.
따라서 MemberServiceImpl를 전혀 알지 못하므로 AOP 적용 대상이 아니다.
target(hello.aop.member.MemberServiceImpl): target 객체를 보고 판단한다.
target 객체가MemberServiceImpl` 타입이므로 AOP 적용 대상이다.
영상 오류 정정
영상에서 JDK Proxy는 MemberService를 알 수 없다고 설명했는데, MembmerServiceImpl을 알 수 없다로 정정합니다.
✅ MembmerService 인터페이스 지정
this(hello.aop.membmer.MembmerService): 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 적용 대상이다.
✅ThisTargetTest
packagehello.aop.pointcut;
importhello.aop.member.annotation.MemberService;
importlombok.extern.slf4j.Slf4j;
importorg.aspectj.lang.ProceedingJoinPoint;
importorg.aspectj.lang.annotation.Around;
importorg.aspectj.lang.annotation.Aspect;
importorg.junit.jupiter.api.Test;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.boot.test.context.SpringBootTest;
importorg.springframework.context.annotation.Import;
/** * application.properties * spring.aop.proxy-target-class=true CGLIB * spring.aop.proxy-target-class=false JDK 동적 프록시 */@Slf4j@Import(ThisTargetTest.ThisTargetAspect.class)
@SpringBootTest(properties = "spring.aop.proxy-target-class=false") //JDK 동적 프록시//@SpringBootTest(properties = "spring.aop.proxy-target-class=true") //CGLIBpublicclassThisTargetTest {
@AutowiredMemberServicememberService;
@Testvoidsuccess() {
log.info("memberService Proxy={}", memberService.getClass());
memberService.hello("helloA");
}
@Slf4j@AspectstaticclassThisTargetAspect {
//부모 타입 허용@Around("this(hello.aop.member.MemberService)")
publicObjectdoThisInterface(ProceedingJoinPoinjoinPoint) throwsThrowable {
log.info("[this-interface] {}", joinPoint.getSignature());
returnjoinPoint.proceed();
}
}
//부모 타입 허용@Around("target(hello.aop.member.MemberService)")
publicObjectdoTargetInterface(ProceedingJoinPointjoinPoint) throwsThrowable {
log.info("[target-interface] {}", joinPoint.getSignature());
returnjoinPoint.proceed();
}
//this: 스프링 AOP 프록시 객체 대상//JDK 동적 프록시는 인터페이스를 기반으로 생성되므로 구현 클래스를 알 수 없음//CGLIB 프록시는 구현 클래스를 기반으로 생성되므로 구현 클래스를 알 수 있음@Around("this(hello.aop.member.MemberServiceImpl)")
publicObjectdoThis(ProceedingJoinPointjoinPoint) throwsThrowable {
log.info("[this-impl] {}", joinPoint.getSignature());
returnjoinPoint.proceed();
}
//target: 실제 target 객체 대상@Around("target(hello.aop.member.MemberServiceImpl)")
publicObjectdoTarget(ProceedingJoinPointjoinPoint) throwsThrowable {
log.info("[target-impl] {}", joinPoint.getSignature());
returnjoinPoint.proceed();
}
}
this, target은 실제 객체를 만들어야 테스트 할 수 있다. 테스트에서 스프링 컨테이너를 사용해서 target, proxy 객체를 모두 만들어서 테스트해보자.
properties = {"spring.aop.proxy-target-class=false"} : application.properties 에
설정하는 대신에 해당 테스트에서만 설정을 임시로 적용한다. 이렇게 하면 각 테스트마다 다른 설정을 손쉽게 적용할 수 있다
spring.aop.proxy-target-class=false : 스프링이 AOP 프록시를 생성할 때 JDK 동적 프록시를 우
선 생성한다. 물론 인터페이스가 없다면 CGLIB를 사용한다.
spring.aop.proxy-target-class=true : 스프링이 AOP 프록시를 생성할 때 CGLIB 프록시를 생성한
다. 참고로 이 설정을 생략하면 스프링 부트에서 기본으로 CGLIB를 사용한다. 이 부분은 뒤에서 자세히 설명한다
@SpringBootTest(properties = "spring.aop.proxy-target-class=false") //JDK 동적 프록
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
Uh oh!
There was an error while loading. Please reload this page.
1️⃣1️⃣ this, target
✅ 정의
✅ 설명
✅ this vs target
단순히 타입 하나를 정하면 되는데, this와 target은 어떤 차이가 있을까 ?
✅ 프록시 생성 방식에 따른 차이
✅ MemberService 인터페이스 지정
✅ MembmerServiceImpl 구체 클래스 지정
this(hello.aop.member.MemberServiceImpl) : proxy 객체를 보고 판단한다.
JDK 동적 프록시로 만들어진 proxy 객체는 MemberService 인터페이스를 기반으로 구현된 새로운 클래스다.
따라서 MemberServiceImpl를 전혀 알지 못하므로 AOP 적용 대상이 아니다.
target(hello.aop.member.MemberServiceImpl): target 객체를 보고 판단한다.
target 객체가MemberServiceImpl` 타입이므로 AOP 적용 대상이다.
✅ MembmerService 인터페이스 지정
✅ MemberServiceImpl 구체클래스 지정
proxy 객체는 MemberServiceImpl 를 상속 받아서 만들었기 때문에 AOP가 적용된다. this 가 부모 타입을허용하기 때문에 포인트컷의 대상이 된다.
MemberServiceImpl 타입이므로 AOP 적용 대상이다.
✅ThisTargetTest
this, target은 실제 객체를 만들어야 테스트 할 수 있다. 테스트에서 스프링 컨테이너를 사용해서 target, proxy 객체를 모두 만들어서 테스트해보자.
properties = {"spring.aop.proxy-target-class=false"} : application.properties 에
설정하는 대신에 해당 테스트에서만 설정을 임시로 적용한다. 이렇게 하면 각 테스트마다 다른 설정을 손쉽게 적용할 수 있다
spring.aop.proxy-target-class=false: 스프링이 AOP 프록시를 생성할 때 JDK 동적 프록시를 우선 생성한다. 물론 인터페이스가 없다면 CGLIB를 사용한다.
spring.aop.proxy-target-class=true: 스프링이 AOP 프록시를 생성할 때 CGLIB 프록시를 생성한다. 참고로 이 설정을 생략하면 스프링 부트에서 기본으로 CGLIB를 사용한다. 이 부분은 뒤에서 자세히 설명한다
✅spring.aop.proxy-target-class= false
this(hello.aop.member.MemberServiceImpl)로 지정한
[this-impl]부분이 출력되지 않는 것을 확인할 수 있다.✅ spring.aop.proxy-target-class=true, 또는 생략(스프링 부트 기본 옵션)
All reactions