지금까지 사용중인 객체가 proxy객체 인지 아닌지 구별하기 위해
instanceof 연산자로 SpringProxy 타입을 비교해서 구분 했는데
이미 그렇게 구분해서 값을 돌려주는게 있었네요...

org.springframework.aop,.support.AopUtils

'Spring > AOP' 카테고리의 다른 글

Proxy 객체인지 확인하려면...?  (0) 2009.01.21
Spring AOP - aop스키마 기반  (0) 2008.01.14
Spring AOP - @AspectJ  (0) 2007.12.31
Spring AOP APIs - ProxyFactoryBean, AutoProxy  (0) 2007.12.31
Spring AOP APIs - Advisor  (2) 2007.12.31
Spring AOP APIs - Pointcut  (0) 2007.12.31
Posted by 째코

댓글을 달아 주세요

Spring AOP는 다른 AOP 프레임워크와 달리 런타임시 Target 객체의 Porxy 객체를 생성함으로써 AOP 를 구현합니다. Proxy 객체를 생성할때는 CGLIB 또는 JDK DynamicProxy를 이용하게 되는데 만약 Target 클래스가 인터페이스 기반이라면 JDK DynamicProxy를 이용하게 되고 인터페이스 기반이 아니라면 CGLIB를 이용하게 됩니다. 하지만 인터페이스 기반이라도 CGLIB를 이용하도록 설정 가능 합니다.

ProxyFactoryBean
Proxy 객체를 만들 수 있는 가장 기본적인 클래스는 ProxyFactoryBean 입니다. 다른 FactoryBean들과 마찬가지로 내부에서 생성된 객체를 리턴하며 단지 Proxy된 객체를 리턴한다는 것만 다릅니다.
앞서 나왔던 Advisor를 이용해 Proxy객체를 만들어 보겠습니다.

위 예제에서 ProxyFactoryBean의 target 프로퍼티와 interceptorNames 프로퍼티를 이용해
대상 객체인 Foo와 advice+pointcut의 조합인 advisor를 설정하고 있습니다.
이제 컨테이너로부터 foo를 요청하면 Porxy객체가 리턴 될 것입니다.

ProxyFactoryBean은 설정 가능한 수많은 프로퍼티가 존재합니다.
그 중에서 중요한 것들만 알아 보겠습니다.
target - Proxy의 Target bean
interceptorNames[] - 적용할 Advisor bean
interfaces[] & proxyInterfaces[] - Target 객체에 추가로 구현할 인터페이스
                                                  인터페이스 추가 구현시 반드시 CGLIB 이용해야 함
exposeProxy - Target 객체가 현재 Proxy에 접근 가능한지 여부. Target 클래스 내에서
                      AopContext.currentProxy() 메소드로 현재 Porxy에 접근 가능
proxyTargetClass - CGLIB의 사용 여부. Target 클래스가 인터페이스 기반이라도 이 프로퍼티를 통해
                             CGLIB를 이용할 수 있음

여기서 중요한점이 있습니다.
Target 클래스가 인터페이스를 구현하고 있지 않더라도 interfaces[] & proxyInterfaces[] (이하 interfaces[]) 를 설정하고 proxyTargetClass를 false로 설정할 경우 JDK DynamicProxy(이하 JDK Proxy)를 이용해 Proxy 객체를 만들게 됩니다. 이 때 문제가 발생하는데 Target 객체를 설정한 인터페이스로 다운캐스팅이 불가능 할 뿐만 아니라 인터페이스의 메소드 호출시 추상메소드로 판단하고 예외가 발생 됩니다. 이유는 JDK Proxy가 Proxy객체를 만들 때 Target 클래스가 인터페이스 기반이 아닐경우 intefaces[]에 지정된 인터페이스를 Target 객체 구현하지 못해서 발생하는 문제입니다. 따라서 JDK Proxy가 사용되는 상황이라면 반드시 Target 클래스가 인터페이스 기반이여야 합니다. 만약 위와 같은 상황에서 CGLIB를 이용한다면 Target 클래스에 인터페이스 구현이 제대로 이루어지며 문제는 발생하지 않습니다.
그리고 Target 클래스가 이미 구현하고 있는 인터페이스는 interfaces[] 프로퍼티에 설정할 필요가 없습니다.
이러한 이유로 interfaces에 대한 설명을 "Target 객체에 추가로 구현할 인터페이스" 라고 했습니다.

위 사실들을 토대로 Introdction Advisor를 지정할 경우를 생각해 봅시다.
Introduction Advisor를 interceptorNames[]에 지정 할 경우 Target객체에서 추가 기능이 정의된 인터페이스로 다운캐스팅 하기 위해 interfaces[]에 해당 인터페이스를 지정 할 필요가 없습니다. 왜냐면 Proxy객체 생성 과정중 Advisor가 IntroductionAdvisor일 경우 validateIntroductionAdvisor 메소드에서
IntroductionAdvice가 구현한 인터페이스를 interfaces[] 프로퍼티에 자동으로 등록하기 때문입니다.
이 경우 Target 클래스가 해당 인터페이스를 구현하지 않은 상황이므로 proxyTargetClass 프로퍼티는 true로 설정 해야 합니다.

Global Advisor 사용하기
interceptorNames 프로퍼티의 값으로 와일드 카드를 이용 할 수 있습니다.

AutoProxy

ProxyFactoryBean은 AOP를 적용해야 할 bean이 많을 경우 모든 bean에 대해 설정 하는것은 매우 귀찮은
일 입니다. 다행히 Spring AOP에서는 자동으로 Proxy객체를 생성시켜주는 기능을 가진 bean을 제공 합니다.
아래 두가지 AutoProxy는 ProxyFactoryBean의 속성들이 대부분 존재 합니다.

BeanNameAutoProxyCreator
beanNames[] 에 지정된 bean들에 한해서 interceptorNames[] 로 지정된 advisor가 적용된 Proxy객체를
생성 합니다. beanNames[] 에 와일드카드(*)가 사용 가능한 특징이 있습니다.

DefaultAdvisorAutoProxyCreator
단지 등록만 해두면 advisor들을 찾아서 자동으로 대상을 결정하고 Proxy객체를 생성 합니다.

'Spring > AOP' 카테고리의 다른 글

Spring AOP - aop스키마 기반  (0) 2008.01.14
Spring AOP - @AspectJ  (0) 2007.12.31
Spring AOP APIs - ProxyFactoryBean, AutoProxy  (0) 2007.12.31
Spring AOP APIs - Advisor  (2) 2007.12.31
Spring AOP APIs - Pointcut  (0) 2007.12.31
Spring AOP APIs - Advice  (0) 2007.12.31
Posted by 째코

댓글을 달아 주세요

<aop:scoped-proxy /> 요소는 이전 글(링크) 에서 소개했는데
이번엔 좀 더 자세히 작동 방식에 대해 정리해 보겠습니다.
아래 설정을 보시면 bar가 참조하는 foo의 scope는 session 입니다.

이 설정을 기반으로 한 WebApplicationContext 컨테이너는 foo를 생성할 때
<aop:scoped-proxy /> 요소가 있으므로 foo에 대한 Proxy 객체를 생성 합니다.
Foo(Proxy)객체에 적용된 intercept는 다음과 같습니다.(CGLIB 사용 할 경우)
Cglib2AopProxy$DynamicAdvisedInterceptor
Cglib2AopProxy$DynamicUnadvisedInterceptor
Cglib2AopProxy$SerializableNoOp
Cglib2AopProxy$SerializableNoOp
Cglib2AopProxy$AdvisedDispatcher
Cglib2AopProxy$EqualsInterceptor
Cglib2AopProxy$HashCodeInterceptor

여기서 중요한 것은
DynamicUnadvisedInterceptor 입니다.
DynamicUnadvisedInterceptor 가 적용 되는 메소드는 Object 클래스의 toString(), clone(), finalize() 메소드와 사용자정의 public 메소드(non-static) 입니다.

DynamicUnadvisedInterceptor의 intercept 구현 내용은 크게 2단계로 나뉩니다.
첫번째로 getTarget() 호출 두번째로 원본 메소드 호출이 되겠습니다.
getTarget() 메소드는 최종적으로 AbstractBeanFactory 의 getBean() 메소드를 호출 합니다. 따라서 해당 bean에 정의된 scope가 현재scope(session, request) 에 의해 새로운 객체를 생성하거나 기존의 객체를 돌려 줍니다. 그리고는 돌려 받은 target객체를 통해서 원래 메소드를 호출 합니다.

<lookup-method />는 자신이 직접 Proxy 객체가 되는 반면
<aop:scoped-proxy />는 Proxy 객체를 만들어 주입하는 차이가 있군요

'Spring > Core' 카테고리의 다른 글

LifeCycle 확장  (0) 2007.12.17
LifeCycle  (0) 2007.12.17
<aop:scoped-proxy /> 작동 방식  (5) 2007.12.14
Bean scopes  (0) 2007.12.14
메소드 삽입  (0) 2007.12.14
Autowiring  (0) 2007.12.10
Posted by 째코

댓글을 달아 주세요

  1. 기선 2007.12.15 12:16  댓글주소  수정/삭제  댓글쓰기

    흠.. Beans.xml 파일도 보고 싶지만, 제가 아는 것만 말씀드리면 다음과 같습니다.

    저 엘리먼트는 싱글톤 객체가 Session이나 Request Scope의 객체에 의존할 때 해당 객체에게 사용합니다.

    왜냐면, 싱글톤 객체는 한 번만 만들어지기 때문에 Session이나 Request 스콥의 객체를 세션이 만들어지거나 요청이 올때마다 새로 만드러야 하는데 그러지 못하기 때문입니다.

    의아해 하시는 이유는 짐작이 됩니다.
    그에 대한 해결책으로는 ProxyFactoryBean을 잘 사용해보시면 될 것 같습니다.
    이 부분은 저도 공부를 좀 해야되서;;; 뭐라고 확실하게 말씀드리진 못하겠네요. (__)/

  2. 기선 2007.12.15 12:19  댓글주소  수정/삭제  댓글쓰기

    저도 좀 햇갈려서 위에 댓글을 잘못 달았었는데요. 수정을 좀 했습니다.

    <aop:scope-proxy/>를 prototype 스콥의 객체에 사용하면 어이없는 결과를 볼 수 있습니다. 아마 위 처럼 메소드 호출 할 때마다 새로운 객체를 생성하기 때문에 완전히 Stateless한 객체를 보게 됩니다. 어떻게 사용할 수가 없죠.

    저 엘리먼트는 오직 session과 request 스콥을 위한 엘리먼트 입니다. 예전에 웹 애플리케이션 작성할 때 두, 세번 사용해본적이 있는데 그 당시엔 원하는대로 잘 사용해서 이렇게 오래 생각해본적이 없었던 것 같습니다. :)

    http://java-x.blogspot.com/2007/01/spring-prototype-beans-with-singletons_23.html

    위 글을 보시면 도움이 되실지도...

    • 째코 2007.12.15 16:46 신고  댓글주소  수정/삭제

      아항 그렇군요
      session과 request에만 적용 되는거라면 옳바른 작동 방식이 맞네요 ㅎㅎ
      희안하게 어제 이 글을 쓰는 시점에서 웹으로 session scope로 주고 테스트 할때도 분명 객체를 마구마구 생성했었는데 이제 잘되네요 -_-;; 아마도 배포가 재대로 이루어지지 않고 그냥 돌렸나 봅니다. ;;
      이 색션이 래퍼런스에서 해석되지 않아서 코드만보고 한 제가 잘못했네요. 알려주셔서 감사합니다

    • 째코 2007.12.15 18:29 신고  댓글주소  수정/삭제

      글 내용 수정했습니다.