일전에 @Transactional 을 사용하며 겪게되는 실수를 정리하며 간략하게 넘어갔었던 프록시 패턴에 대하여 정리해보려고 한다.
스프링 AOP 프레임워크는 Proxy 기반으로 동작하며 앞서 자주 언급한 @Transactional 도 Proxy 패턴으로 동작한다.
위 코드에서 주석만 띡 달면 메소드 시작전 트랜젝션이 열리게 되며 종료될때까지 데이터의 정합성을 유지하는 상태로 변경또는 수정이 가능하며 트랜젝션이 종료되면 데이터베이스에 커밋까지 해준다 이게 어떻게 가능한 것일까?
앞서 언급한대로 메서드가 시작되기전 트랜젝션 프록시가 changeName 메소드를 인터셉트하여 비즈니스 로직시작 종료 시점에 코드를 삽입하게 된다.
@Transactional 또한 위에 언급한 두가지 방식중 하나로 동작하고 있다 공식문서에 따르면 Dynamic Proxy 를 이용한다고 되어있지만 디버그모드를 통해 타고들어가다보면 결국 CGLib 방식을 이용해 프록시가 등록되어있다.
두 방식의 차이는 무엇일까?
위의 코드를 실행하자 마자 CGLibAopProxy 객체에서 메소드 시작전 Intercept 하여 객체의 액세스 제어권을 가져간것을 볼 수 있다.
스프링 공식문서에 따르면 CGLib DynamicProxy 둘다 self-invocation 굳이 번역하자면 자가 발동정도로 볼 수 있겠다 뭐 의미야 어찌됐건 self-invocation 을 지원하지 않는다라고 명시되어있다.
매우 중요한 문구인데 무심코 사용하는 경우가 있다 프록시의 정상작동을 원한다면 호출 Target 외부에 있는 다른 객체가 Target 객체를 호출해야지만 원하는 방향으로 동작시킬 수 있다.
References