프록시객체 self-invocation

김성지·2023년 3월 1일
0

그냥공부

목록 보기
8/10

이 주제는 인터넷에 검색하면 엄청많이 나온다
그만큼 매우 유명한 topic이라고 하더라

근데 몰랐었다..

그래서 다른 분들의 글을 부분부분 옮겨적고
나름대로 궁금한 점들을 직접 해보는 과정을 기록해두려한다

참고자료들은 밑에 링크를 달아두었다

준비과정

Service 작성

@Service
public class AopService{
    public void method1(){
        System.out.println("method1 호출");
        method2();
    }
    @TestAspect
    public void method2(){
        System.out.println("method2 호출");
    }
}

AopService의 method1에서
this.method2()를 호출한다.

프록시객체 생성을 위해 AOP 작성

@Aspect
@Component
public class TestAspect {
    @Pointcut("execution(void sungjee.test.jpatest.AOPTest.AopService*.method2(..))")
    public void testPointcut(){
    }

    @Before("testPointcut()")
    public void before(){
        System.err.println("advice 호출");
    }
}

테스트 코드 작성

@SpringBootTest
@EnableAspectJAutoProxy
@RequiredArgsConstructor
@TestConstructor(autowireMode = TestConstructor.AutowireMode.ALL)
public class TestAop {
    private final AopService aopService;
    private final ApplicationContext context;
    @Test
    public void testAop(){
        AopService contextObject = context.getBean(AopService.class);
        assertTrue(contextObject instanceof AopService);
        //assertTrue(Proxy.isProxyClass(contextObject.getClass()));
        aopService.method1();
        System.out.println(contextObject.getClass()+"빈에 등록된 객체");

    }
}

이때 CGLIB으로 생성된 프록시객체는
주석처리된 부분이 올바르게 작동하지 않는다.
(Proxy.isProxyClass(contextObject.getClass()))

JDK dynamic proxy로 생성된 객체만 true를 반환한다.

테스트 실행시 출력창

콘솔창에

method1 호출
advice 호출
method2 호출 

이 찍혀야 될 것 같지만

aspect 걸어둔 부분이 제대로 작동하지 않는다.

찾아본 이유들

  1. https://gmoon92.github.io/spring/aop/2019/04/01/spring-aop-mechanism-with-self-invocation.html

우선 aop로 감싸진 부분(메서드)이 있으므로
AopService는 빈에 등록될 때 proxy 객체로 등록된다

테스트 코드에서 aopService.method1()을 호출할 때는
proxyaopSerivce.method1()을호출하지만proxy_aopSerivce.method1()을 호출하지만proxy_aopSerivce.method1() 내부과정에서
this.method2()를 호출할 때
$proxy_aopService의 method2()를 호출하는 것이아닌
실제 클래스의 method2()를 즉 원본을 호출해버려서

걸어둔 aspect가 실행되지 않는 것으로 이해했다.

  1. https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-understanding-aop-proxies
The key thing to understand here is that the client code 
inside the main(..) method of the Main class has a reference 
to the proxy. This means that method calls on that object 
reference are calls on the proxy. As a result, the proxy can 
delegate to all of the interceptors (advice) that are 
relevant to that particular method call. However, once the 
call has finally reached the target object (the SimplePojo 
reference in this case), any method calls that it may make on 
itself, such as this.bar() or this.foo(), are going to be 
invoked against the this reference, and not the proxy. This 
has important implications. It means that self-invocation is 
not going to result in the advice associated with a method 
invocation getting a chance to run.

읽고나서 궁금한점이
proxy 객체가 생성되고
프록시객체의 method1()이 실행되면서
method2()가 호출되면
왜 원본객체의 메소드가 호출되는지 잘 이해가 안간다.

그래서 동적으로 생성된 자바객체를 디컴파일해서 확인하려고 했더니

일단 런타임에 생성되는 객체는 디스크에 저장하지 않고
메모리상에 올라가있다고한다.

그래서 클래스가 생성되는 시점에 클래스를 디스크에 저장하는 코드를 넣으면 된다는데

...

그래서 그냥 아 그렇구나 하고 지금단계에서는 일단 넘어가려고 한다

발생할 수 있는 상황들

@cacheable 이나
@Transcational 이나

Spring AOP가 실행되는 상황..

프록시 객체가 생성되는 상황이면 전부 해당되는 것 같다.

참고자료

https://gmoon92.github.io/spring/aop/2019/04/01/spring-aop-mechanism-with-self-invocation.html

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#aop-understanding-aop-proxies

0개의 댓글

관련 채용 정보