spring로 검색한 결과 :: 시소커뮤니티[SSISO Community]
 
SSISO 카페 SSISO Source SSISO 구직 SSISO 쇼핑몰 SSISO 맛집
추천검색어 : JUnit   Log4j   ajax   spring   struts   struts-config.xml   Synchronized   책정보   Ajax 마스터하기   우측부분

회원가입 I 비밀번호 찾기


SSISO Community검색
SSISO Community메뉴
[카페목록보기]
[블로그등록하기]  
[블로그리스트]  
SSISO Community카페
블로그 카테고리
정치 경제
문화 칼럼
비디오게임 스포츠
핫이슈 TV
포토 온라인게임
PC게임 에뮬게임
라이프 사람들
유머 만화애니
방송 1
1 1
1 1
1 1
1 1
1

spring로 검색한 결과
등록일:2008-06-10 17:14:32
작성자:
제목:[SPRING] FactoryBean을 이용한 AOP 클래스 생성 예제


1. advice를 이용한 생성
  
  UserService target = new UserServiceImpl();
  
  ProxyFactory pf = new ProxyFactory();
  
  pf.addAdvice(new UserLoggingAdivce());
  pf.addAdvice(new EmailNotificationThrowAdvice());
  pf.setTarget(target);
  
  UserService userService = (UserService) pf.getProxy();
  
  
: advice 클래스와 target 클래스만을 가지고 위빙시키고 있다. 아마 내부적으로 디폴트 포인트컷을 적용하여 advisor를 만들어서
셋팅하고 있을 것이라 생각이 됨.

 

2. advisor를 생성  
  UserService target = new UserServiceImpl();
  target.setUserDAO(mock);

  ProxyFactory pf = new ProxyFactory();
  
  Pointcut loggingPC = new UserLoggingPointcut();
  Advisor loggingAdvisor = new DefaultPointcutAdvisor(loggingPC, new UserLoggingAdvice());
  pf.addAdvisor(loggingAdvisor);
  
  Pointcut emailPC = new EmailNotificationPointcut();
  Advisor emailAdvisor =
   new DefaultPointcutAdvisor(emailPC, new EmailNotificationThrowsAdvice());
  pf.addAdvisor(emailAdvisor);

  pf.setTarget(target);

  UserService userService = (UserService) pf.getProxy();
  
: 어드바이스를 적용 할 포인트컷 클래스를 생성하고, 이것을 어드바이스와 결합하여 어드바이저를 생성하고 있다.


그러면 AOP를 이용해서 spring의 Factory Bean 인터페이스를 구현하는 방법을 알아보세..

- Factory Bean 인터페이스는

Object getObject() throws Exception;
Class getObjectType();
boolean isSingleton();

3개의 메소드만 가지고 있는 인터페이스 이다.

 

이것을 이용하면 AOP의 적용도 선언적으로 구현 할 수가 있다.

 

public class AOPFactoryBean implements FactoryBean, BeanFactoryAware, InitializingBean {
 
 private boolean singleton = true;
 
 private Object instance;
 
 private String[] interceptorNames;
 
 private Object target;
 
 private BeanFactory beanFactory;
 
 public void setBeanFactory(BeanFactory beanFactory){
  this.beanFactory = beanFactory;
 }
 
 public void setInterceptorNames(String[] interceptorNames) {
  this.interceptorNames = interceptorNames;
 }
 
 public void setTarget(Object target) {
  this.target = target;
 }
 
 public void afterPropertiesSet() throws Exception {
  if( target ==  null ) {
   throw new NullPointerException("Target 클래스 이름을 입력해야 합니다.");
  }
  
  if ( (interceptorNames == null ) && (interceptorNames.length == 0) ) {
   instance = target;
  } else {
   ProxyFactory pf = new ProxyFactory();
   pf.setTarget(target);
   
   for( int i=0; i < interceptorNames.length; i++ ) {
    Advisor advisor = getAdvisor(interceptorNames[i]);
    if ( advisor != null ) {
     pf.addAdvisor(advisor);
    }
   }
   
   instance = pf.getProxy();
  }  
 }
 
 private Advisor getAdvisor(String interceptorName){
  Object advObject = beanFactory.getBean(interceptorName);
  if( advObject instanceof Advisor) {
   return (Advisor)advObject;
  } else if(advObject instanceof Advice) {
   return new DefaultPointcutAdvisor((Advice)advObject);
  } else {
   return null;
  }
 }
 
 public Object getObject() throws Exception {
  return instance;
 }

 public Class getObjectType() {
  if( instance != null ) {
   return instance.getClass();
  }
  
  return null;
 }

 public boolean isSingleton() {
  return singleton;
 }
 
}

: 이 클래서는 결론적으로 target과 어드바이저가 위빙된 클래스를 리턴하게 되는데 여기서 target은 userServiceImpl이 되겠다.


xml에서 각 id에 대한 빈 설정이 되어 있고, set 메서드가 있으므로 setter 인젝션을 이용해 셋팅이 될 것이다.  


ApplicationContext에서 getBean을 통해 userservice를 호출하게 되는데 한번 따라가봅시다.

 

userservice를 lookup하면 xml에 의해
 <bean id="userService" class="net.javajigi.advice.AOPFactoryBean">
  <property name="target">
   <ref local="userServiceTarget" />
  </property>
  <property name="interceptorNames">
   <list>
    <value>userLoggingAdvisor</value>
    <value>emailNotificationThrowsAdvice</value>
   </list>
  </property>
 </bean>
이 부분을 바라보게 될 것이다. userService는 보는 바와 같이 AOPFactoryBean으로 지정되어 있고 이 클래스는


target클래스와 interceptroNames (String형 어드바이스 클래스를 가리킬 것임)를 내부 인자로 가지고 있게 된다.

 

AOPFactoryBean 클래스는 위에서 예제로 보여지고 있는 바로 그 클래스이다.

위 클래스를 보면
setTarget과 setInterceptorNames 메서드를 통해 IOC Setter injection을 하게 되는데
그렇다면 target 이것과 interceptorNames은 무엇이냐. xml에 정의된 바와 같이
target은
  <bean id="userServiceTarget" class="net.javajigi.user.service.UserServiceImpl">
  <property name="userDAO">
   <ref local="userDAO" />
  </property>
 </bean>
이것이 될 것이고

interceptorNames의
userLoggingAdvisor 는 나중에
<bean id="userLoggingAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
        <property name="advice">
            <ref local="userLoggingAdvice"/>
        </property>
        <property name="pointcut">
            <bean class="net.javajigi.advice.UserLoggingPointcut"/>
        </property>
    </bean>
이것과 매칭될 것이다.

 

 저 상태에서는 단지 이름만 String으로 셋팅되게 된다. (String[])

 그리고 요기서 userLoggingAdvice는 다시
 <bean id="userLoggingAdvice" class="net.javajigi.advice.UserLoggingAdvice" />
 
그리고
emailNotificationThrowsAdvice 는
<bean id="emailNotificationThrowsAdvice" class="net.javajigi.advice.EmailNotificationThrowsAdvice"/>
이 나중에 매칭 될 것이지만 일단 이 상태에서는 이름의 String만 셋팅된다.

 

interceptorNames는 위 AOPFactoryBean을 보면 알겠지만 String[] 형 이기 때문에 xml에서 List 인자를 가질 수 있다.

이렇게 인자들이 셋팅이 되면
afterPropertiesSet이 호출이 되는데..

----------------------------------------------------------------------------------------------
 public void afterPropertiesSet() throws Exception {
  if( target ==  null ) {
   throw new NullPointerException("Target 클래스 이름을 입력해야 합니다.");
  }
  
  if ( (interceptorNames == null ) && (interceptorNames.length == 0) ) {
   instance = target;
  } else {
   ProxyFactory pf = new ProxyFactory();
   pf.setTarget(target);
   
   for( int i=0; i < interceptorNames.length; i++ ) {
    Advisor advisor = getAdvisor(interceptorNames[i]);
    if ( advisor != null ) {
     pf.addAdvisor(advisor);
    }
   }
   
   instance = pf.getProxy();
  }  
 }
----------------------------------------------------------------------------------------------
일단 target이 없으면 Exception
interceptornames가 없으면 그냥 target만 리턴 (aop 적용 대상이 없기 때문)

그렇지 않으면 바로 맨 위에 정리한 비슷한 코드가 나오게 된다.
ProxyFactory pf = new ProxyFactory();
를 구현하여 일단 setTarget으로 target을 셋팅하고

for문을 돌면서 pf에다가 어드바이저를 셋팅하게 되는데

interceptorNames를 가지고 셋팅하고 있다.
getAdvisor는

--------------------------------------------------------------------------------------------------
private Advisor getAdvisor(String interceptorName){
  Object advObject = beanFactory.getBean(interceptorName);
  if( advObject instanceof Advisor) {
   return (Advisor)advObject;
  } else if(advObject instanceof Advice) {
   return new DefaultPointcutAdvisor((Advice)advObject);
  } else {
   return null;
  }
 }
--------------------------------------------------------------------------------------------------

보면 위 xml에서 list에서 설정된 이름을 가지고 beanFactory에서 해당 클래스를 가져오게 되는데. 일단
첫번째 셋팅 된 userLoggingAdvisor이 넘어오면 이 이름을 가지고 LookUp하게 되고 이때 xml에 정의 된데로
userLoggingAdvisor는
 <bean id="userLoggingAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
        <property name="advice">
            <ref local="userLoggingAdvice"/>
        </property>
        <property name="pointcut">
            <bean class="net.javajigi.advice.UserLoggingPointcut"/>
        </property>
    </bean>
를 가져오게 된다. 이 클래스는 어드바이저 클래스이기 때문에 advice클래스와 포인트컷 클래스를 같이 인자로 가지고 있고 이를 통해
어드바이저 클래스가 생성된다.
(advice는  <bean id="userLoggingAdvice" class="net.javajigi.advice.UserLoggingAdvice" />)

때문에 위 getAdvisor 메서드에서 첫번쨰 if문에 의해 위 userLoggingAdvisor 클래스가 리턴되고 이 때 사용되는 포인트컷과 어드바이스는
위와 같다.

즉 맨위에 써놓은
Advisor loggingAdvisor = new DefaultPointcutAdvisor(loggingPC, new UserLoggingAdvice());

이런 것이 발생하여 리턴해준다는 것이다.

다음 interceptornames인
emailNotificationThrowsAdvice는 xml 설정에 의해서
<bean id="emailNotificationThrowsAdvice" class="net.javajigi.advice.EmailNotificationThrowsAdvice"/>
이 클래스의 인스턴스가 리턴이 되는데
위 클래스는 Advice를 구현한 클래스이고 if문에 의해
return new DefaultPointcutAdvisor((Advice)advObject);
이것이 실행된다. 즉 포인트컷이 없이 디폴트로 advice클래스를 가지고 advisor를 만들어 리턴해주는 것이다.

이것을 받은 afterSetProperties 메서드 에서는
pf.addAdvisor(advisor);
메서드를 통해 pf에 어드바이저를 셋하고

instance = pf.getProxy();

이렇게 위빙이 끝난 인스턴스를 리턴하게 되는 것이었다.

하지만, 여기서
userService = (UserService) ctx.getBean("userService");

이렇게 호출을 하는데 userService라는 ID를 가지는 빈은 AOPFactoryBean이다. 그런데 UserService로 캐스팅을 하고 있는데
이것이 가능할까..

이는 BeanFactory 클래스의 getBean 메서드는 내부적으로

FactoryBean클래스의 getObject를 실행하도록 지원하고 있기 때문이다.
(즉, AOPFactoryBean는 FactoryBean을 구현 했기 때문에 AOPFactoryBean의 getObject가 실행된다는 뜻..)

아...인터페이스 대박..ㅠㅠ


호출
 protected void setUp() throws Exception {
  String[] paths = { "/WEB-INF/AOPFactoryBean.xml" };
  ctx = new ClassPathXmlApplicationContext(paths);

  userService = (UserService) ctx.getBean("userService");
 }
 
설정파일
 <bean id="userServiceTarget" class="net.javajigi.user.service.UserServiceImpl">
  <property name="userDAO">
   <ref local="userDAO" />
  </property>
 </bean>

 <bean id="userService" class="net.javajigi.advice.AOPFactoryBean">
  <property name="target">
   <ref local="userServiceTarget" />
  </property>
  <property name="interceptorNames">
   <list>
    <value>userLoggingAdvisor</value>
    <value>emailNotificationThrowsAdvice</value>
   </list>
  </property>
 </bean>
   
    <bean id="userLoggingAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
        <property name="advice">
            <ref local="userLoggingAdvice"/>
        </property>
        <property name="pointcut">
            <bean class="net.javajigi.advice.UserLoggingPointcut"/>
        </property>
    </bean>
   
    <bean id="userLoggingAdvice" class="net.javajigi.advice.UserLoggingAdvice" />

 <bean id="emailNotificationThrowsAdvice" class="net.javajigi.advice.EmailNotificationThrowsAdvice"/>

 

 

-출처 : 나... - 긁어서 java 코드 형식을 지원하는 에디터에 붙여넣어 보시면

조금 보기 낫습니다 -_-;;;;

 

 

사족 : spring을 하게 되면

인터페이스 A가 있고 이를 구현한 클래스 Aimpl과 Bimpl, Cimpl이 있다고 가정할때

 

A a = new Aimpl();

A b = new Bimpl();

A c = new Cimpl();

 

나중에 이를 받아서 쓸때는

 

OtherClass oc = new OtherClass();

 

oc.doit(a);

oc.doit(b);

oc.doit(c);

 

받는 곳에서는

 

public void method(A aa) {

....

  aa...(); // (상세적으로 구현한 클래스가 뭔지 신경쓰지 않아도 됨)

}

 

이런식의 사용이 가능한 업캐스팅 원리를 알지 못 하면 정말 이해하기 힘들다 -_-;

 

 

만약 업캐스팅이 아니라면 위 경우는

 

public void method(Aimple aa) {...}

public void method(Bimple bb) {...}

public void method(Cimple cc) {...}

 

이렇게 세개의 메서드가 준비되어야 하고

 

A a = new Aimpl();

A b = new Bimpl();

A c = new Cimpl();

 

이부분도

Aimple a = new Aimple();

Bimple b = new Bimple();

Cimple c = new Cimple();

 

이렇게 되어야 하겠지..

 

출처 : http://blog.naver.com/need4spd/60044762449