반응형
Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
31 |
Tags
- Spring Boot
- findFirst
- Save Action
- vaultTemplate
- Stream
- LogInterceptor
- AOP target
- ClientHttpRequestInterceptor
- 쓰레드 안전
- AOP this
- @AutoConfiguration
- 개방/폐쇄 원칙
- restTemple
- java
- spring
- Thread Safety
- gradle
- fotmatter
- AOP 매개변수
- RestTemplate
- JsonType
- auto configuration
- Starter
- AccessLevel
- AOP
- 포맷터
- jpa
- JsonStringType
- ResponseBodyAdvice
- findAny
Archives
- Today
- Total
맨땅에 헤딩하는 개바른자
[AOP] this, target 본문
반응형
[AOP] this, target는 스프링 프레임워크에서 사용되는 개념입니다.
- this: 메소드 실행 객체**(프록시객체)**를 참조하는 키워드입니다.
- target: 실제 메소드가 구현된 객체를 참조하는 키워드입니다.
이를 이용하여, 스프링에서 AOP를 구현할 때, 메소드 실행 전/후에 추가적인 작업을 수행할 수 있습니다.
예를 들어, 로깅 기능을 추가하고 싶다면, AOP를 활용하여 해당 메소드 실행 전/후에 로깅을 수행할 수 있습니다.
이처럼, [AOP] this, target는 스프링에서 AOP를 구현하는 데 필수적인 개념이므로, 이를 잘 이해하고 활용하는 것이 중요합니다.
this와 target은 다음과 같이 적용타입 하나를 정확하게 지정해야 한다.
this(hello.aop.member.MemberService)
target(hello.aop.member.MemberService)
- 별표와 같은 (*) 표현식은 사용할 수 없다.
- 부모 타입을 허용한다.
- 실제 사용성은 낮은 편인다.
프록시 생성 방식에 따른 차이
- JDK 동적 프록시 : 인터페이스가 필수이고, 인터페이스를 구현한 프록시 객체를 생성한다.
- CGLIB : 인터페이스가 있어도 구체 클래스를 상속 받아서 프록시 객체를 생성한다.
먼저 JDK 동적프록시 적용을 알아보자
- this(MemberService) O
- proxy 객체를 보고 판단한다. this는 부모타입을 허용하기 때문에 AOP가 적용된다.
- targer(MemberService) O
- target 객체를 보고 판단한다. this는 부모타입을 허용하기 때문에 AOP가 적용된다.
- this(MemberServiceImpl) X
- proxy 객체를 보고 판단한다. JDK 동적 프록시로 만들어진 proxy 객체를 MemberService 인터페이스를 기반으로 구현된 새로운 클래스다. 따라서 MemberServiceImpl를 전혀 알지 못하므로 AOP 적용대상이 아니다.
- targer(MemberServiceImpl)
- target 객체를 보고 판단한다. target객체가 MemberServiceImpl타입이므로 AOP 적용 대상이다.
CGLIB 프록시 적용을 알아보자
- this(MemberService) O
- proxy 객체를 보고 판단한다. this는 부모타입을 허용하기 때문에 AOP가 적용된다.
- targer(MemberService) O
- target 객체를 보고 판단한다. this는 부모타입을 허용하기 때문에 AOP가 적용된다.
- this(MemberServiceImpl) X
- proxy 객체를 보고 판단한다. CGLIB로 만들어진 만들어진 proxy 객체를 MemberServiceImpl를 상속받아서 만들었기 때문에 AOP가 적용된다. this가 부모 타입을 허용하기 때문에 포인트컷의 대상이 된다.
- targer(MemberServiceImpl)
- target 객체를 보고 판단한다. target객체가 MemberServiceImpl타입이므로 AOP 적용 대상이다.
예제코드
https://github.com/ymwoo88/study-springboot-aop/tree/feature/스프링-AOP-this-target
package hello.aop.pointcut;
import hello.aop.member.MemberService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.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=true")
//@SpringBootTest(properties = "spring.aop.proxy-target-class=false")
public class ThisTargetTest {
@Autowired
MemberService memberService;
@Test
void success() {
log.info("memberService Proxy={}", memberService.getClass());
memberService.hello("helloA");
}
// 참고로 스프링트에서 프로식 사용 시 무조건 CGLIB로 동작하게되어있어서 JDK동적프록시로 돌아가게끔 별도 설정이 필요하다
@Slf4j
@Aspect
static class ThisTargetAspect {
// 부모타입을 허용
@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 doThisImpl(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[this-impl] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
// 구현체타입
@Around("target(hello.aop.member.MemberServiceImpl)")
public Object doTargetImpl(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[target-impl] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
}
}
결과
- JDK 동적 프록시
2023-03-29 21:06:04.718 INFO 65949 --- [ Test worker] hello.aop.pointcut.ThisTargetTest : memberService Proxy=class com.sun.proxy.$Proxy53
2023-03-29 21:06:04.722 INFO 65949 --- [ Test worker] h.a.p.ThisTargetTest$ThisTargetAspect : [target-impl] String hello.aop.member.MemberService.hello(String)
2023-03-29 21:06:04.722 INFO 65949 --- [ Test worker] h.a.p.ThisTargetTest$ThisTargetAspect : [target-interface] String hello.aop.member.MemberService.hello(String)
2023-03-29 21:06:04.722 INFO 65949 --- [ Test worker] h.a.p.ThisTargetTest$ThisTargetAspect : [this-interface] String hello.aop.member.MemberService.hello(String)
- CGLIB 프록시
2023-03-29 21:09:59.480 INFO 69151 --- [ Test worker] hello.aop.pointcut.ThisTargetTest : memberService Proxy=class hello.aop.member.MemberServiceImpl$$EnhancerBySpringCGLIB$$dc929420
2023-03-29 21:09:59.485 INFO 69151 --- [ Test worker] h.a.p.ThisTargetTest$ThisTargetAspect : [target-impl] String hello.aop.member.MemberServiceImpl.hello(String)
2023-03-29 21:09:59.485 INFO 69151 --- [ Test worker] h.a.p.ThisTargetTest$ThisTargetAspect : [target-interface] String hello.aop.member.MemberServiceImpl.hello(String)
2023-03-29 21:09:59.486 INFO 69151 --- [ Test worker] h.a.p.ThisTargetTest$ThisTargetAspect : [this-impl] String hello.aop.member.MemberServiceImpl.hello(String)
2023-03-29 21:09:59.486 INFO 69151 --- [ Test worker] h.a.p.ThisTargetTest$ThisTargetAspect : [this-interface] String hello.aop.member.MemberServiceImpl.hello(String)
정리
프록시를 대상으로 하는 this의 경우 구체 클래스를 지정하면 프록시 생성 전략에 따라서 다른 결과가 나올 수 있다.
반응형
'JAVA > AOP' 카테고리의 다른 글
[AOP] 실전예제 Service단 파라미터 Null체크 사용기 (1) | 2023.04.25 |
---|---|
[AOP] 실전예제 로그TRACE (0) | 2023.04.18 |
[AOP] 매개변수 전달 (0) | 2023.03.29 |
[AOP] @annotation (0) | 2023.03.23 |
[AOP] @target @within (0) | 2023.03.23 |