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
- JDBC
- 알고리즘
- Thymeleaf
- 그리디
- jpa
- transaction
- JPQL
- Greedy
- SpringBoot
- 백준
- Proxy
- 인프런
- Spring Boot
- pointcut
- Android
- spring
- QueryDSL
- 스프링 핵심 원리
- 자바
- kotlin
- 김영한
- Exception
- springdatajpa
- db
- AOP
- http
- java
- 스프링
- 스프링 핵심 기능
- Servlet
Archives
- Today
- Total
개발자되기 프로젝트
[스프링AOP 포인트컷] this, target 본문
1. 정의
- this : 스프링 빈 객체(스프링 AOP 프록시)를 대상으로 하는 조인 포인트
- target : Target 객체(스프링 AOP 프록시가 가르키는 실제 대상)를 대상으로 하는 조인 포인트
2. 설명
- this , target 은 다음과 같이 적용 타입 하나를 정확하게 지정해야 한다.
this(hello.aop.member.MemberService)
target(hello.aop.member.MemberService)
- * 같은 패턴을 사용할 수 없다.
- 부모 타입을 허용한다.
3. this vs target
- 스프링에서 AOP를 적용하면 실제 target 객체 대신에 프록시 객체가 스프링 빈으로 등록된다.
- this 는 스프링 빈으로 등록되어 있는 프록시 객체를 대상으로 포인트컷을 매칭한다.
- Target 은 실제 target 객체를 대상으로 포인트컷을 매칭한다.
4. 프록시 생성 방식에 따른 차이
- 스프링은 프록시를 생성할 때 JDK 동적 프록시와 CGLIB를 선택할 수 있다.
- 둘의 프록시를 생성하는 방식이 다르기 때문에 차이가 발생한다.
- JDK 동적 프록시: 인터페이스가 필수이고, 인터페이스를 구현한 프록시 객체를 생성한다.
- CGLIB: 인터페이스가 있어도 구체 클래스를 상속 받아서 프록시 객체를 생성한다.
5. JDK 동적 프록시 & this, 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 인터페이스를 기반으로 구현된 새로운 클래스다.
따라서 프록시는 구현체인 MemberServiceImpl 를 전혀 알지 못하므로 이 경우는 AOP 적용 대상이 아니다.
매칭이 안된다. - target(hello.aop.member.MemberServiceImpl)
target 객체를 보고 판단한다.
target 객체가 MemberServiceImpl 타입이므로 AOP 적용 대상이다.
6. CGLIB & this, 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 객체를 보고 판단한다.
CGLIB로 만들어진 proxy 객체는 MemberServiceImpl 를 상속 받아서 만들었기 때문에 AOP 적용가 적용된다.
this 가 부모 타입을 허용하기 때문에 포인트컷의 대상이 된다. - target(hello.aop.member.MemberServiceImpl)
target 객체를 보고 판단한다. target 객체가MemberServiceImpl 타입이므로 AOP 적용 대상이다.
7. 정리
- 프록시를 대상으로 하는 this 의 경우
- 구체 클래스를 지정하면 프록시 생성 전략에 따라서 다른 결과가 나올 수 있다
8. Test
/**
* application.properties
* spring.aop.proxy-target-class=true CGLIB(default)
* 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")//CGLIB
public class ThisTargetTest {
@Autowired
MemberService memberService;
@Test
void success(){
log.info("memberService Proxy={}", memberService.getClass());
memberService.hello("helloA");
}
@Slf4j
@Aspect
static class ThisTargetAspect{
//this 부모타입 허용
@Around("this(hello.aop.member.MemberService)")
public Object doThisInterface(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[this-interface] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
//target 부모타입 허용
@Around("target(hello.aop.member.MemberService)")
public Object doTargetInterface(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[target-interface] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
//this 부모타입 허용
@Around("this(hello.aop.member.MemberServiceImpl)")
public Object doThis(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[this-concrete] {}", joinPoint.getSignature());
return joinPoint.proceed();
}
//target 부모타입 허용
@Around("target(hello.aop.member.MemberServiceImpl)")
public Object doTarget(ProceedingJoinPoint joinPoint) throws Throwable {
log.info("[target-concrete] {}", joinPoint.getSignature());
return joinPoint.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를 사용한다.
JDK 동적 프록시 사용 결과
- JDK 동적 프록시를 사용하면 this(hello.aop.member.MemberServiceImpl) 로 지정한 [thisimpl]
부분이 출력되지 않음
[target-concrete] String hello.aop.member.MemberService.hello(String)
[target-interface] String hello.aop.member.MemberService.hello(String)
[this-interface] String hello.aop.member.MemberService.hello(String)
CGLIB 사용 결과
[target-concrete] String hello.aop.member.MemberServiceImpl.hello(String)
[target-interface] String hello.aop.member.MemberServiceImpl.hello(String)
[this-concrete] String hello.aop.member.MemberServiceImpl.hello(String)
[this-interface] String hello.aop.member.MemberServiceImpl.hello(String)
9. GitHub: 220108 this, target
'인프런 > [인프런] 스프링 핵심 원리 - 고급' 카테고리의 다른 글
[스프링AOP실전] 로그 출력 AOP (0) | 2022.01.09 |
---|---|
[스프링AOP실전] 예제 만들기 (0) | 2022.01.08 |
[스프링AOP 포인트컷] 매개변수 전달 (0) | 2022.01.07 |
[스프링AOP 포인트컷] bean (0) | 2022.01.07 |
[스프링AOP 포인트컷] @annotation, @args (0) | 2022.01.07 |
Comments