Whiteship's Note


스프링 AOP에서 this와 target 포인트컷 표현식 구분 하시는 분?

Spring/Chapter 7 : 2008. 11. 5. 11:42


Pro Spring 2.5에서 this 표현식에 대한 정의입니다.

the semantics of the this pointcut are such that it would match any method execution on an object whose class matches the specified expression, but how could we match any class in the com package and its subpackages? Therefore, the only allowed syntax is this(class-name),

Pro Spring 2.5에서 target 표현식에 대한 정의 입니다.

Because the target expression defines a pointcut that would match execution of any method on an object whose class matches the specified expression, we cannot use the wildcards.

뭐가 달라 보이나요??? 앞 부분에 어순이 약간 바뀐것 빼고는 도무지 차이를 알 수가 없습니다.

레퍼런스를 보죠.

this - limits matching to join points (the execution of methods when using Spring AOP) where the bean reference (Spring AOP proxy) is an instance of the given type

target - limits matching to join points (the execution of methods when using Spring AOP) where the target object (application object being proxied) is an instance of the given type

레퍼런스는 그나마 좀 차이가 보입니다. this일 때는 프록시 객체고 target 일 때는 프록시를 적용할 타겟 객체가 주체가 됩니다.

즉, this 표현식은 주어진 타입에 해당하는 스프링 AOP Proxy의 조인포인트에 대응하는 표현식이고.. target 표현식은 주어진 타입에 해당하는 타겟 객체의 조인포인트에 대응하는 표현식이라는 것인데..

어차피 프록시 객체의 타입이 곧 타겟 객체의 타입과 동일하기 때문에 결과는 똑같을 것 같은데 말이죠. 차이를 모르겠습니다. 아흐.. 머리야..

마지막으로 AspectJ 문서를 보겠습니다.

this(Type or Id)
    Picks out each join point where the currently executing object (the object bound to this) is an instance of Type, or of the type of the identifier Id (which must be bound in the enclosing advice or pointcut definition). Will not match any join points from static contexts.

target(Type or Id)
    Picks out each join point where the target object (the object on which a call or field operation is applied to) is an instance of Type, or of the type of the identifier Id (which must be bound in the enclosing advice or pointcut definition). Will not match any calls, gets, or sets of static members.

this는 동적이고 target은 정적으로 타입을 지칭하는 차이밖에 없어보입니다. 흠.. 과연..

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="applicationContext.xml")
public class FooAspectTest {

    @Autowired
    FooBean fooBean;

    @Test
    public void isProxy(){
        assertTrue(fooBean instanceof Advised);
        fooBean.hi();
    }

}


@Aspect
public class FooAspect {

    @Pointcut("this(org.opensprout.spring.aop.thisandtarget.FooBean)")
    public void thisPointcut(){}

    @Before("thisPointcut()")
    public void say(){
        System.out.println("this pointcut executed.");
    }

}

스프링 AOP에서는 this를 target으로 고쳐도 똑같이 동작합니다. 콘솔에 메시지가 한 번 출력되죠. 그러나 AJDT로 실행하면, this의 경우 같은 메시지가 세 번 찍히고, target의 경우 같은 메시지가 네 번찍힙니다. 일단 두 번은 클래스 로딩이나 생성자 호출 조인포인트에서 찍혔다고 생각하고, 하나는 테스트에서 hi 호출 할 때 찍힌거고 가장 의아한건 target 표현식일 때의 마지막 한 번.

디버깅을 돌려본 결과 저 테스트에 두 번 들어가던데;; 왜 그런지 몰겠네요. 아~ 미궁이로 구나..
top

  1. Favicon of http://helols.tistory.com BlogIcon helols 2008.11.05 14:54 PERM. MOD/DEL REPLY

    헛;; 그떄 스터디에서 미궁으로 빠졌던 부분이네요;;ㅋ
    안되면 S1A에 로드존슨님에 물어보심이^^;; 그러고보니 한달도 안남았네요 ... S1A... ;; ㅠ

    Favicon of http://whiteship.me BlogIcon 기선 2008.11.05 15:26 PERM MOD/DEL

    그러게요. 할 일도 많은데 시간아 멈추어DAO.. ㅠ.ㅠ

Write a comment.


AspectJ의 @DeclareError를 사용해서 컴파일 시점에 아키텍처 에러 검증하자.

AOP : 2008. 10. 21. 11:26


참조: http://www.parleys.com/display/PARLEYS/Home#slide=1;title=Spring%20Architectures;talk=20676612

위 발표자료 내용 주에 아주 잼나는 코드를 건졌습니다. 지난 번 KSUG에서 발표한 내용과 겹치는데 아래 코드는 그때 제가 보여드린 코드보다 좀 더 좋은 것 같아서 가져왔습니다.

@Aspect
public class SystemArchitecture {
  @Pointcut("execution(* configurator.*.*(..))")
  public void configuratorLogic () {}
  @Pointcut("execution(* dao.*.*(..))")
  public void dao() {}
  @Pointcut("within(*.dao.*)")
  public void inDaoLayer() {}
  @Pointcut("call(* *.service.*.*(..))")
  public void callServiceLayer() {}
}


@Aspect
public class Layering {
  @DeclareError("SystemArchitecture.inDaoLayer() && "+
   "SystemArchitektur.callServiceLayer() ")
  public static final String DAOsNotFromServices =
   "DAO must not call Service!";
 @DeclareError(" (call(* java.sql.*.*(..)) && " +
  "!within(*.dao.*) ) ")
  public static final String JdbcOnlyInDAOs =
   "JDBC only in DAOs!";
}

좋은 건 이Aspectj를 사용하면 @DecalreError를 사용해서, 컴파일 시점에 아키텍처 에러를 검증할 수 있다는 것입니다. 제가 준비했던 코드는 cflow를 사용해서 런타임에 검증하는 방법이었습니다. 따라서 테스트 하지 않고 그냥 커밋하면 뭐 어떻게 찾아낼 방법이 없었습니다. 그런데 이 방법을 쓰면 코딩할 때 문제되는 코드를 발견할 수 있으니 훨씬 좋은 것 같습니다. 캬.. 귿..


top

  1. 둥이아빠 2010.06.01 11:57 PERM. MOD/DEL REPLY

    이곳에서 매번 좋은 자료 얻어갑니다^^
    Pro Spring도 잘 보고 있구요..

    하나 질문을 드리려고 하는데요...

    AspectJ의 DeclareError를 이용해서 여러가지 개발 정책들을 정의했는데요.
    현재 Framework 개발 중이다 보니..
    해당 Aspect 클래스를 컴파일해서 Jar로 같이 배포하려고 하고 있습니다.

    Aspect 클래스가 컴파일 되는 시점에서는 DeclareError가 잘 발생이 되고 Cross References View에도 관련된 클래스들이 보여지는데요

    Aspect 클래스 소스를 Framework 소스들과 같이 컴파일해서 특정 이클립스 프로젝트에 Jar로 배포하면 DeclareError가 발생 되고 있지 않습니다.

    배포시에 특별하게 신경써야 하는 부분이 있는지도 궁금합니다^^

    Favicon of http://whiteship.me BlogIcon 기선 2010.06.01 12:49 PERM MOD/DEL

    흠.. 글쎄요.
    패키징 하면서 아마 포인트컷이 제대로 안먹힌것이 아닐까 싶은데요. 포인트컷 테스트를 해서 원하는 지점에 포인트컷이 걸리는지 확인해봐야겠습니다.

    http://whiteship.me/2378

    제목은 엉뚱하지만 저 안에 보시면 포인트컷 테스트 하는 방법이 들어있습니다.

    Favicon of http://lckymn.com BlogIcon Kevin 2010.06.01 18:45 PERM MOD/DEL

    Aspects를 묶어서 jar로 일종의 모듈을 만드셨고,
    그 모듈을 사용하는 프로젝트에도 위빙이 되어야 할경우,
    프로젝트상에서 aspect 적용되게 컴파일 해주셔야 하구요.
    ajc 컴파일 하실때 -aspectpath 옵션을 사용해서
    그 모듈 파일(들)을 설정해 줘야합니다.

    maven과 aspectj-maven-plugin를 쓰시면,
    aspectLibraries 파라미터를 사용하시면 되구요.

    그런데, 여기 언급한 문제가
    http://whiteship.me/2641#comment6903603
    발생할 수도 있습니다.

    Favicon of http://whiteship.me BlogIcon 기선 2010.06.01 21:31 PERM MOD/DEL

    흠. 그건 AspectJ로 @Aspect를 사용할 때 이야기 같군요.

    @Aspect를 스프링 AOP에서 사용한다면 그런 옵션을 줄필요가 없을 것 같아요. 스프링에서 제공하는 @Transaction이나 @Configurable 처리용 Aspect들이 아무런 별도 옵션 없이도 잘 도는거 보면.. 그렇게 생각이 되네요.

    @Aspect를 패킹해서 써본적이 없어서 원; ㅋ

  2. 둥이아빠 2010.06.01 15:43 PERM. MOD/DEL REPLY

    답변 감사드립니다^^

    Favicon of http://whiteship.me BlogIcon 기선 2010.06.01 21:31 PERM MOD/DEL

    잘 해결되시길!

Write a comment.


AOP를 설명하는 그림 두 장

AOP : 2008. 10. 4. 18:24


역사, 이론, 개념... 등등도 중요하지만, 무엇보다.. '감'이 중요한거 아닐까요. 딱 보고 '감'이 잡힐 만하면 충분하다고 봅니다. 그 뒤에 정말 궁금해서 역사, 이론, 개념들을 살펴보면 되겠죠. 처음부터 장황하게 이러 저러해서 이러 저러한걸 말들었고 어쩌구 저쩌구...  제가 봤었던 AOP 관련 자료 중에 가장 AOP에 대한 '감'을 잡게 해준 그림은 아래와 같은 그림입니다.

사용자 삽입 이미지
애니매이션 기능을 사용해서, 각각의 (횡단)로직들이 여러 클래스에 분산되어 들어가는 모습을 보여주면 더 멋질 것 같습니다.

사용자 삽입 이미지
캬오.. AOP에 대한 '감'을 잡기엔 충분한 그림이 아닌가 생각해봅니다. 이 그림을 보고도 AOP가 OO를 대체하는 프로그래밍 패러다임으로 인식한다면... 그건 좀.. 흠...
top

TAG AOP
  1. Favicon of http://ecogeo.tistory.com BlogIcon 서영아빠 2008.10.04 23:15 PERM. MOD/DEL REPLY

    http://www.zdnet.co.kr/builder/dev/java/0,39031622,39147106,00.htm
    저는 토비님이 쓰신 글을 보고 감이 잡혔지요.. ^^ 토비님 짱!

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2008.10.05 09:51 PERM MOD/DEL

    네, 좋은 글이죠. 저두 저 글 읽고 개념 잡는데 많은 도움을 받았습니다. 사부님 짱!

Write a comment.


4. @AspectJ 사용하는 초간단 AOP 예제

AOP : 2008. 1. 8. 17:18


사용자 삽입 이미지

JDK 6에서도 테스트 해봤습니다.
Spring 2.5 jar 파일을 사용했으며, AspectJ 관련 라이브러리는 lib폴더에 있는 것들을 사용했습니다.

결과화면
사용자 삽입 이미지
오랜만에 배치기 노래도 듣을 수 있고 좋군요.

저 예제를 돌리고 나서 얼마나 신났었는지 그 때의 기분을 고대로 느낄 수 있었습니다.
댓글 주셔서 감사합니다.
================================================================================

Spring Reference 6장에 있는 코드들을 테스트 해보기 위해 초간단 예제를 만들어 봅니다.
참조 : http://www.infoq.com/articles/Simplifying-Enterprise-Apps

소스 코드 보기

실행 결과
만나서 반~갑~습니다.
저는 백~기~선입니다.
AOP 죽~ 여~ 줍니다~

이 프로그램이 돌아가려면 Spring을 사용하기 때문에 이 전 글에서 추가 했던 spring.jar파일과 commons-logging.jar가 필요하며 AspectJ를 사용하고 있기 때문에 'AspectJ 설치 폴더'/lib or Spring-with-dependencies를 설치하셨다면 'Spring 설치 폴더'/lib/aspectj/ 안에 있는 aspectjrt.jar 와 aspectjweaver.jar 파일을 classpath에 추가해야 합니다.

예제를 돌렸네요. 아고 기뻐라.




top

TAG AOP, SpringAOP
  1. Favicon of http://decoder.tistory.com BlogIcon decoder 2007.01.10 10:27 신고 PERM. MOD/DEL REPLY

    ㅎㅎ 노래가 신나군요...

    Favicon of http://whiteship.tistory.com/ BlogIcon 기선 2007.01.10 12:13 PERM MOD/DEL

    넵 헤헷.. 쉬면서 하시라구요. :P

  2. 짱가 2007.01.16 23:54 PERM. MOD/DEL REPLY

    한글이 깨지는 경우는 어떻게 하셨어요?

    Favicon of http://whiteship.tistory.com/ BlogIcon 기선 2007.01.17 00:54 PERM MOD/DEL

    한글이 깨지셨어요?..
    전 그런적이 없었는데요..흠..--;

    Favicon of http://whiteship.tistory.com/ BlogIcon 기선 2007.01.17 01:06 PERM MOD/DEL

    소스코드를 돌린 환경을 말씀드리면..
    Eclipse 3.2 WTP
    JDK 1.5.0_09
    Spring 2.0 입니다.

  3. Favicon of https://kekedie.tistory.com BlogIcon kekedie 2008.01.08 16:26 신고 PERM. MOD/DEL REPLY

    에러 나는데요. 잘 해결이 안되네요..

    Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'keesun' defined in class path resource [firstSpringAOP/aopAppContext.xml]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 can't find referenced pointcut greeting
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory$1.run(AbstractAutowireCapableBeanFactory.java:485)
    at java.security.AccessController.doPrivileged(Native Method)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:455)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:251)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:169)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:248)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:170)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:413)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:735)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:369)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:122)
    at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:66)
    at firstSpringAOP.TestFirstAOP.main(TestFirstAOP.java:9)

  4. Favicon of https://kekedie.tistory.com BlogIcon kekedie 2008.01.08 16:36 신고 PERM. MOD/DEL REPLY

    JDK6이 문제였네요...;;;;;;;;

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.01.08 17:12 신고 PERM MOD/DEL

    엇 이상하네요.
    전 JDK6에서도 돌아가는데요;;;;;;;;;

  5. Favicon of https://kekedie.tistory.com BlogIcon kekedie 2008.01.08 18:12 신고 PERM. MOD/DEL REPLY

    이상하네...;; 덧글이 계속 지워지다가 또 되네요..휴~
    @Before("execution(* *..Hans.*(..))";)
    @AfterReturning("execution(* *..Hans.*(..))";)
    이렇게 설정하니까 테스트 통과하더라구요. greeting()메소드 명을 적어주면 실패구요.

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2008.01.08 22:41 PERM MOD/DEL

    흠.. 글쿤요;;
    이상하네요 ㅎㅎ;;;

  6. 자바철학자 2009.07.07 14:35 PERM. MOD/DEL REPLY

    수고하십니다. 매번 좋은 정보 잘 보고 있습니다. 수고하세요

    whiteship2000@gmail.com 2009.07.07 15:27 PERM MOD/DEL

  7. Favicon of http://blog.naver.com/hulint BlogIcon 나창훈 2010.09.15 13:01 PERM. MOD/DEL REPLY

    안녕하세요~ 이곳에서 좋은 예제 좋은 설명 잘 보고 있습니다~

    한가지 궁금한게 있어서요..

    지금 main메소드에서 sayName메소드를 호출할때 AOP가 동작하게끔 되어 있는데

    main메소드를 호출할때도 AOP가 동작하게 할수 있나요?

    지금 컨트롤러에 AOP를 적용해서 로그인 체크를 해볼려고 하는데

    @RequestMapping(value=LIST_URL)
    public ModelAndView handleRequest(HttpServletRequest req){

    이 메소드에 대한 AOP가 동작(?) 하지 않아서 여쭤봅니다.

    제가 AOP에 대한 개념을 잘못 잡은건지;;;

Write a comment.


JDBC 함수 실행 전에, Hibernate 세션 플러시하기

Spring/TSE 2007 : 2008. 1. 8. 11:41


요약/번역/참조 : Before a JDBC operation, flush the Hibernate Session (includes TSE example code)

문제 상황


ORM을 사용하는 코드와 ORM을 사용하지 않는 코드(생 SQL)를 한 뭉탱이 한 트랜잭션으로 처리할 때, 데이터베이스에 있는 데이터를 사용할 수 없는 이슈가 발생할 수 있다.

섞어서 사용해야 하는 이유

많은 엔터프라이즈 애플리케이션에서 도메인 모델을 저장하고 (심지어 복잡한 도메인 모델을) 가져올 때 ORM을 사용하고 있다.

그렇다고해서 일반 SQL을 사용하는 것이 완전히 사라지진 않을 것이며, 다음의 경우에는 일반 SQL이 필요하다.
- 테스트 코드 : ORM 툴을 사용하여 객체를 DB에 넣었을 때, SQL을 사용하여 전체 레코드 수를 가져와서 비교하는 등의 테스트를 할 때 용이하다.
- 스토어드 프로시져 사용시 : 프로젝트에서 스토어드 프로시져를 사용하는 경우가 많았고 이것을 ORM과 혼용하길 원하는 경우가 많았다. 예를 들어, 새로운 객체들을 집어넣은 뒤에, 가용한 레코드들과 새로운 넣은 레코드들의 연관이 필요한 경우가 있다.(뭔소린지..흠;;)
- 상당히 많은 객체에 대한 함수 사용시 : 백만개의 주문을 true 에서 false로 변경할 때, 저자는 ORM보다 SQL을 선호한다고 합니다.(하긴 뭐 이게 더 편할 수도 있겠지..)

ORM과 SQL 혼용시 발생하는 이슈

DB는 비어있다고 가정하고, 다음의 수도Pseudo 코드를 보자.
start transaction

create part with name Bolt
associate with ORM engine (i.e. save using entity manager)

update part set stock = 15 where name='Bolt'

end transaction

위에서 두 수도 코드의 update문(SQL문)은 위에서 Bolt라는 부품을 Entity Manager에게 저장하라고 했는데도 불구하고 실패하게 됩니다.

Entity Manager가 저장을 요청한 순간에 부품 객체를 저장하는 것이 아니라 트랜잭션이 끝날 때 저장하기 때문입니다.

ORM의 이런 속성을 write-behind 라고 합니다. 이 개념때문에, 사용할 수 있을 것 같다고 생각한 순간인데도 실제로는 사용하지 못하는 경우가 발생합니다.(위 상황으로 유추할 때, write-behind는 DB에 접속하는 빈도수를 줄이기 위해 사용하는 기술 같습니다.)

올바른 해결책

단순하게 다음과 같이 위의 수도 코드를 두 개의 트랜잭션으로 나누는 것을 생각할 수 있습니다.
start transaction
create part with name Bolt
associate with ORM engine (i.e. save using entity manager)
end transaction

start transaction
update part set stock = 15 where name='Bolt'
end transaction

하지만 이 것은 틀린 답입니다. 원자성을 깨트렸습니다. (그렇다면, 위의 두 트랜잭션을 nested transaction으로 가지는 하나의 트랜잭션으로 묶으면 되지 않을까?)

올바른 해결책은 SQL 쿼리를 실행하기 전에, ORM 엔진이 변경사항을 DB에 저장하도록 하는 것입니다. JPA도 하이버네이트 처럼 이런 방법을 제공하는데, 이게 바로  Flushing 입니다. 이것을 사용하여 수도 코드를 다음과 같이 고칠 수 있습니다.

start transaction

create part with name Bolt
associate with ORM engine (i.e. save using entity manager)

*** flush

update part set stock = 15 where name='Bolt'

end transaction

해결책 적용하기

사용자 삽입 이미지
수도 코드를 시퀀스 다이어그램으로 나타낸 것입니다.

자 이제 flush() 메소드를 추가해야 하는데, 어디에 추가해야 할까요? addPart() 메소드 안의 맨 뒤에 추가할까요? 아니면 updateStock() 메소드 안에서 UPDATE 문 바로 뒤에 둘 까요?

두 방법 다 안 좋습니다.
- addPart() 메소드 안에 넣는 방법은 write-behind 방식을 깨트립니다. 그러면 여러 개의 부품을 하나의 트랜잭션에서 추가할 때 최적화를 할 수 없습니다.
- updateStock() 메소드 안에 넣는 방법이 조금 더 나아보이겠지만, 만약 한 트랜잭션에 SQL 문이 여러 개면 어떨까요? flush()가 의미가 있나요?
사용자 삽입 이미지
결론적으로 필요한 것은 세 가지(부품 추가, 부품 수정, 세션 플러시)인데, 이 요구 사항을 만족시키기 위해 코드를 수정할 수 있는 부분은 두 곳 뿐입니다. 바로 여기가 Aspect-Oriented 가 제 몫을 하는 지점입니다. AOP 기술은 코드를 추가할 수 있는 추가적인 공간을 제공합니다. 즉 별도의 모듈로 위의 요구사항을 해결할 수 있도록 해줍니다.

세 개의 요구사항을 각각의 모듈로 처리하기

새로운 부품 추가하기
private SessionFactory sessionFactory;

public void insertPart(Part p) {
        sessionFactory.getCurrentSession().save(p);
}

부품 가격 수정하기
private SimpleJdbcTemplate jdbcTemplate;

public void updateStock(Part p, int stock) {
        jdbcTemplate.update("update stock set stock = stock + ? where number=?",
                stock, p.getNumber());
}

세션 동기화하기

정리해보면, 'JDBC을 할 떄마다, 세션에 dirty 상태이면 flush해야한다.' 이것을 좀 더 정리하면, 'JDBC 작업을 수행하기 전에, 세션이 dirty 상태이면 flush 하라.' 이 것을 다음과 같이 언제, 어디서, 무엇을로 쪼갤 수 있습니다.

    * 언제: before
    * 어디서: a call to a JDBC operation
    * 무엇을: flush a dirty Hibernate session

이렇게 쪼개두면, AspectJ로 구현하기 쉽습니다. 이것을 AspectJ로 구현하면 다음과 같습니다.
public aspect HibernateStateSynchronizer {

        private SessionFactory sessionFactory;
      
        public void setSessionFactory(SessionFactory sessionFactory() {
                this.sessionFactory = sessionFactory;
        }

        pointcut jdbcOperation() :
                call(* org.springframework.jdbc.core.simple.SimpleJdbcTemplate.*(..));
              
        before() jdbcOperation() {
                Session session = sessionFactory.getCurrentSession();
                if (session.isDirty()) {
                        session.flush();
                }
        }
}

생각해 볼 것

먼저, 위의 Aspect는 SimpleJdbcTemplate의 모든 메소드 호출에 적용을 했는데, 특정 애노테이션이 붙은 메소드에만 적용할 수 있도록 포인트컷을 수정할 수 있습니다. (예) execution(@JdbcOperation *(..))

두 번째로 생각해 볼 것은 가용한 하이버네이트 세션이 없을 때 입니다. SessionFactory.getCurrentSession() 은 항상 새로운 세션을 생성해 줍니다. 그런데 SessionFactory 없거나, 세션이 아예 만들어지지 않았을 때에도 위의 Aspect가 동작하려면, 스프링에서 제공하는 SessionFactoryUtils 를 사용해서 세션을 가져오도록 할 수 있습니다. (어지럽...)

소스 코드

HibernateStateSynchronizer 는 AspectJ를 사용해서 구현했고, 간단하게 Spring AOP를 사용하여 구현할 수도 있습니다.

HibernateCarPartsInventoryTests 는 위의 수도 코드를 테스트 했고, aspect가 가용하면 테스트가 통과하고 가용하지 않다면 테스트는 실패합니다.

현재는 before 어드바이스를 주석처리 해놨기 때문에 테스트가 fail 할 것이고, pom.xml을 보면 Maven AspectJ 플러그인이 있는데, 이게 버전 충돌이 나지만 무시해도 됩니다.


감상문

대단합니다. 어쩜 이리 깔끔하게 정리할 수 있는지, 사진도 멋있네요.(전 여자를 좋아합니다.) Spring AOP를 공부하면서 AspectJ로 살짝 공부하긴 했지만, 실제 언제 어떻게 Aspect를 적용할지는 많이 고민해보지를 않았었습니다. 그냥 막연하게 레퍼런스에 나와있는 정도의 로깅, 트랜잭션, 보안.. 그나마 이러한 것들도 이미 스프링에서 만들어서 제공해주고 있기 때문에 더더욱 별 고민이 없었죠. 이 글은 AOP 초딩같은 저에게 진짜 Aspect Orient Programming이 뭔지 한 수 보여주는 것 같습니다. Alef Arendsen 당케쉔.

'Spring > TSE 2007' 카테고리의 다른 글

Simplifying CRUD Web Applications  (0) 2008.02.13
JDBC 함수 실행 전에, Hibernate 세션 플러시하기  (0) 2008.01.08
top

Write a comment.


Aspect Oriented Programming with Spring

Spring/Chapter 6 : 2007. 3. 26. 21:23


6.1. Introduction
AOP의 기본 개념과 Spring AOP의 기능과 목표를 이야기 합니다.
Spring AOP는 Proxy 기반입니다.

6.1. Introduction

6.2. @AspectJ support
어노테이션을 사용하여 AspectJ를 사용하는 방법입니다.
Spring AOP가 지원하는 포인트컷은 method 실행 시점뿐입니다.

6.2. @AspectJ support

6.3. Schema-based AOP support
6.2에서 한 내용을 어노테이션 기반이 아닌 XML에 설정을 사용하는 방법 도 있습니다.

6.3. Schema-based AOP support

6.4. Choosing which AOP declaration style to use
어노테이션을 사용할 것인가? XML 설정을 사용할 것인가?
Spring AOP를 사용할 것인가? AspectJ를 사용할 것인가?

6.4. Choosing which AOP declaration style to use

6.5. Mixing aspect types

어노테이션을 사용하는 방법과 XML 설정을 사용하는 방법을 섞어서 사용할 수 있습니다. 심지어 Spring 1.2 버젼 스타일의 프록시와도 같이 사용할 수 있습니다.

6.6. Proxying mechanisms
JDK 프록시 또는 CGLIB을 사용하는데요. 어떤 인터페이스도 구현하지 않았다면 CGLIB 프록시를 사용하고 그렇지 않은 경우에는 JDK 프록시를 사용합니다.

6.6. Proxying mechanisms

6.7. Programmatic creation of @AspectJ Proxies

AspectJProxyFactory를 사용하여 직접 프록시 클래스를 만들 수 있습니다.

6.8. Using AspectJ with Spring applications

AspectJ의 위버와 컴파일러를 사용할 수 있습니다.

6.9. Further Resources

AspectJ home page 여기서 더 많은 내용을 참조 할 수 있습니다.

'Spring > Chapter 6' 카테고리의 다른 글

6.2. @AspectJ support  (0) 2007.04.03
@Around 어드바이스 예제  (0) 2007.04.03
@AfterReturning 어드바이스 만들기  (0) 2007.04.03
@Pointcut Designator  (0) 2007.04.02
@Aspect 붙은 클래스끼리는 상속이 안 됩니다.  (0) 2007.04.02
초간단 @Pointcut 과 @Advice 예제  (0) 2007.04.02
Enabling @AspectJ Support  (0) 2007.04.02
6.3. Schema-based AOP support  (0) 2007.04.01
6.1. Introduction  (0) 2007.04.01
Spring 2.0 AOP  (2) 2007.03.27
Aspect Oriented Programming with Spring  (0) 2007.03.26
top

Write a comment.


Guice와 Spring JavaConfig의 DI 스타일 비교

Spring/Mission : 2007. 3. 21. 09:14


원문은 Guice vs. Spring JavaConfig: A comparison of DI styles 이런 제목으로 올라왔습니다. 다소 기다란 글로 다 읽진 못했습니다. 대강 훝기만 했죠.

Spring In Action 책 초반에 나오는 Knight 예제를 구글 Guice와 Spring의 Configurationd을 XML이 아닌 Java로 어노테이션을 사용하여 할 수 있도록 하는 JavaConfig를 사용하여 비교한 글입니다.

비교된 항목은
1. String Identifier : both Guice and Spring JavaConfig register a win in this category, as neither relies on String identifiers in their configuration and both are easily refactorable through modern IDEs. 둘 다 비슷!

2. Speed/Performance : bean 생성할 때 여러 life cycle을 제공하는 spring이 당연히 단순하게 묶기만 하는 guice보다 느릴 수 밖에... Guice 승!

3. JAR file footprint : 예제(aop와 di사용한 예제)를 돌릴 때 필요한 jar 파일 갯수로..Guice는 딱 두 개 필요하고 spring은 spring-javaconfig.jar, spring-beans.jar, spring-aop.jar, spring-core.jar, spring-context.jar, commons-logging.jar, aopalliance.jar, asm-2.2.2jar, cglib-nodep-2.1_3.jar, and aspectjweaver.jar 좀.. 많이 필요하군요. Guice가 Spring보다 훨씬 가볍다고 할 수 있겠네요. Guice 승!

4. Non-intrusive : AOP에서 injection 되는 클래스가 Guice에 종속된다는 군요. 따라서 재사용 할 수도 없고 Guice.jar파일 없으면 컴파일도 안된다는군요. Spring 승!

5. Third-party beans : Third-party 빈에 속성을 DI 할 때 SpringConfig는 전혀 불편함을 못느꼈으나.. Guice로는 어려웠다. Spring 승!

6. Constant/literal injection : Injection할 때 Guice의 어노테이션 사용이 다소 불편한 것이 있다봅니다. Spring 승!

7. AOP : Spring이나 Guice나 둘 다 AspectJ에는 비교할 수 없지만 Guice는 공식 문서에서도 AOP가 Spring에 비해 좀 딸린다고 알렸고 그게 오히려 단순함을 추구하는 추세라고 했지만...어노테이션 붙이는게 복잡한다 봅니다. Spring 승!

결국 Spring이 DI와 AOP 기능만 Guice와 비교 해봤을 때 4승 1무 2패로 이겼네요.

이글의 밑에는 미친밥이 직접와서 리플도 달아놨군요. 흠.. 거기까지 읽기가 귀찮네요.
top

TAG AOP, DI, Guice, Spring

Write a comment.


Eclipse에서 AspectJ 개발 동영상입니다.

AOP : 2007. 2. 15. 17:46



JCO에서 하는 DevEnv UCC에 올린 동영상입니다. AJDT를 사용해서 간단한 AspectJ 샘플을 만들어 봤습니다.

참조 : http://www.eclipse.org/ajdt/demos/


top

Write a comment.


AOP: Radical Research in Modularity

AOP : 2007. 2. 4. 00:13



Google video에서 engedu[각주:1]로 검색했더니 AOP 강좌가 있었습니다.

흠~ 한시간에 걸쳐 다 보았는데 마지막에 AOP는 모듈화 하는 기술이라고 합니다. 그리고 강의는 주로 AspectJ에 대해서 설명을 하는데 청중들이 질문을 상당히 적극적으로 하는 매우 멋진 강의 였습니다. 그리고 질문 중에 하나는 pointcut이 적용 된 곳이 많아지면 더 복잡해 지지 않느냐는 것과 비슷한 애기가 있었던 것 같은데 IDE(발표자는 Eclipse + AspectJ 플러긴)가 그런 것들을 도와 준다고 하며 시연을 해줍니다. 조금 밖에 못알아 들은 것 같지만 꽤 재밌습니다.
  1. English education의 약어인듯.. [본문으로]
top

  1. Favicon of http://chanwook.tistory.com BlogIcon 찬욱 2007.02.04 01:50 신고 PERM. MOD/DEL REPLY

    한 번 진득히 봐야 겠는걸요~
    흠..영어로 리스닝까지 하시다니~ 대단해요~

    Favicon of http://whiteship.tistory.com/ BlogIcon 기선 2007.02.04 11:07 PERM MOD/DEL

    거의 못알아 들었는데 PPT 화면 보고 대강 먼 얘기 하는구나 하고 때려맞추는거지 ㅋㅋ

  2. Favicon of http://blog.naver.com/paradozz BlogIcon 오승택 2007.02.04 22:04 PERM. MOD/DEL REPLY

    오호 굉장히 좋은 UCC입니다.
    개인적으로 이런 동영상이 액티브한것 처럼 보여서 항상 맘에 듭니다.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2007.02.04 22:12 신고 PERM MOD/DEL

    네~ 강좌 동영상들이 있다는 걸 몇일 전에서야 알았는데 Spring이나 Hibernate 강좌들도 많아졌으면 좋겠어요. :)

Write a comment.


7. @AspectJ 사용하는 초간단 AOP 예제 2

AOP : 2007. 1. 13. 22:27


@AspectJ 를 사용하는 초간단 AOP 예제에서 Pointcut을 선언하고 Advice들에서 해당 Pointcut을 불러가며 사용했었습니다.

    @Pointcut("execution(public * ex1.Human.sayName(..))")
    public void greeting() {
    }

    @AfterReturning("greeting()")
    public void doBeforeOne() {
        System.out.println("AOP 죽~ 여~ 줍니다~");
    }

이렇게 했었는데요. AspectJ에서는 Anonymous Pointcut이라고 하는데 Spring AOP(중에서도@AspectJ)에서도 사용할 수 있습니다. 다음과 같이 Pointcut 이름을 적을 필요 없이 바로 적용될 부분은 Advice에 명시해 주면 됩니다.

    @AfterReturning("execution(public * Human.sayName(..))")
    public void doBeforeOne() {
        System.out.println("AOP 죽~ 여~ 줍니다~");
    }

두 개의 차이점은 위에 기존에 사용해 봤던 방식은 당연히 재사용이 편하다는 것. 그리고 아래의 것은 재사용하기 불편하다는 차이밖에 없는 것 같습니다. :)

Spring AOP를 JDK 6.0 에서 돌리지 마세요 ㅠ.ㅠ Pointcut이 있는데도 없다고 나옵니다. 이것 때문에 정말 황당해 하며 1시간 가량을...'저번에는 분명히 됐는데;; 왜이러지..' 하면서 괴로워 했습니다.
참조 : http://forum.springframework.org/showthread.php?p=92737

top

  1. Favicon of http://seal.tistory.com BlogIcon 물개선생 2007.01.15 08:21 PERM. MOD/DEL REPLY

    흠.. 그렇군요. JDK6에서 테스트를 해보지 않아서 몰랐습니다. 좋은 정보 감사드립니다. ^^*

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2007.01.15 09:10 신고 PERM MOD/DEL

    넵~ 헤헷 :)
    좋은 하루 되세요~

  2. hsk741 2007.08.15 17:05 PERM. MOD/DEL REPLY

    Aspectjweaver.jar 버전 1.5.3에서는 작동하는군요

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2007.08.15 23:07 PERM MOD/DEL

    관련 jar들은 Spring-with-depedencies.zip 에 있던 녀석들을 사용해서 버전은 확인을 못했었네요. :)

  3. Favicon of http://eerien.com/blog/ BlogIcon 이린 2008.01.30 13:12 PERM. MOD/DEL REPLY

    Spring AOP(중에서도@AspecJ)

    에 오타가 있네요. ^-^

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2008.01.30 14:39 신고 PERM MOD/DEL

    감사합니다. (__)/
    수정했습니다.

Write a comment.


5. XML 사용하는 초간단 AOP 예제

AOP : 2007. 1. 9. 20:54


초간단 AOP 예제는 이것으로 세개 째군요.
이전에 올렸던 @AspectJ 사용하는 초간단 예제를 XML 설정 파일을 사용하도록 바꿔봤습니다.

다른 파일들은 모두 같고 MannerAOP파일에서 모든 어노테이션들을 띄어 내고 다음과 같이 수정했습니다.

public class MannerAOP {

       public void beforeSaying() {

             System.out.println("다시 소개 합니다~");

       }

 

       public void afterSaying() {

             System.out.println("AOP ~ 줍니다.");

       }

}

그리고 XML 설정 파일에서 저번에는
<aop:aspectj-autoproxy/>
이렇게 한 줄이 있었는데요. 이 것을 지우고 다음과 같이 설정합니다.

<beans xmlns="http://www.springframework.org/schema/beans"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:aop="http://www.springframework.org/schema/aop"

       xsi:schemaLocation="

http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd

http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">

 

       <!-- this is the object that will be proxied by Spring's AOP infrastructure -->

       <bean id="keesun" class="secondSpringAOP.Keesun" />

 

       <!-- this is the actual advice itself -->

       <bean id="manner" class="secondSpringAOP.MannerAOP" />

 

       <aop:config>

             <aop:aspect ref="manner">

 

                    <aop:pointcut id="greeting"

                           expression="execution(public * secondSpringAOP.Human.sayName(..))" />

 

                    <aop:before pointcut-ref="greeting" method="beforeSaying" />

 

                    <aop:after-returning pointcut-ref="greeting" method="afterSaying" />

 

             </aop:aspect>

       </aop:config>

 

</beans>

결과는 다음과 같습니다.

다시 한 번 소개 합니다~
저는 백~기~선입니다.
AOP 죽~여 줍니다.

이 예제를 돌리기 위해서는 이전에 추가했던 spring.jar, commons-logging.jar, aspectjrt.jar, aspectjweaver.jar 이 것들 이 외에 'Spring-with-dependencies 설치 폴더'/lib/asm/ 안에 있는 asm-2.2.2.jar, asm-commons-2.2.2.jar 파일을 classpath에 추가해 주어야 합니다.

top

TAG AOP, SpringAOP, xml

Write a comment.


3. AspectJ 사용하는 초간단 AOP 예제

AOP : 2007. 1. 6. 16:45


앞에서 보았던 이클립스 플러긴을 잘~ 설치하신 뒤에(이클립스 메뉴를 사용한 설치 추천) 이클립스를 실행합니다.

소스 코드는 기본적으로 AJDT에서 제공해주는 데모 동영상을 참조했습니다.

먼저 이클립스에서 자바 프로젝트를 생성하고 다음과 같이 기본적인 클래스를 작성합니다.

public class Keesun {

       public static void main(String[] args) {

             new Keesun().say();

       }

       private void say() {

             System.out.println("keesun");

       }

}

현재 프로젝트 상태를 보면 다음과 같습니다.
사용자 삽입 이미지
프로젝트를 우클릭하고 나오는 메뉴에서 맨 끝에서 하나위를 보면 AspectJ Tools가 있습니다. 여기서 Convert To AsperctJ Project를 클릭합니다. 그럼 프로젝트가 다음과 같이 바뀝니다.
사용자 삽입 이미지
만약에 위처럼 바뀌지 않았다면 플러긴이 제대로 설치가 되지 않은 것입니다. 그럴땐 다시 설치를 하면 되겠죠 ^^; 저는 처음에 zip파일을 풀어서 설치 했다가 제대로 되지 않아서 엄청 시간을 소비 했답니다. 설치하는데 시간이 조금 걸리더라도 업데이트 사이트를 이용한 설치를 권장합니다.

이제는 Aspect를 만듭니다. 플러긴이 설치 됐다면 클래스를 만들던 아이콘 오른쪽 화살표를 누르면 A가 추가 된 것을 볼 수 있습니다. 그걸 이용해서 Aspect를 만들고 다음과 같이 코딩합니다.

public aspect Manner {

       pointcut callsay(): call (* Keesun.say (..));

 

       before(): callsay () {

             System.out.println("Welecome");

       }

       after(): callsay () {

             System.out.println("Good bye");

       }

}

이제 이전에 작성했던 Keesun 클래스를 실행합니다. 실행 할 때는 Shift + Alt + x , C 를 이용합니다. C가 Aspect Java Application 실행 단축키 입니다. 그런데 J 로 해도 되긴 되네요. :)

결과가 다음과 같이 나오면 정상입니다.
Welecome
keesun
Good bye

만약에 위와 같이 되지 않고.
Exception in thread "main" java.lang.NoClassDefFoundError: org/aspectj/lang/NoAspectBoundException
이런 메시지를 보게 되신 분들은 class path에 aspectjrt.jar 파일을 추가해주면 제대로 실행이 됩니다. 추가하는 방법은 Run 아이콘(녹색 동그라미에 화살표 그려져있는 아이콘)을 클릭하시고 다음 그림처럼 aspectjrt.jar를 추가해 주시면 됩니다.
사용자 삽입 이미지


top

Write a comment.


2. Type of advice

AOP : 2007. 1. 5. 21:19


참조 : Spring Reference 6.1.1 AOP concepts

Before advice : join point 이 전에 실행이 되며 예외를 던지지 않는 이상 join point 이 후에 실행될 작업을 막을 방법이 없습니다.

After returning advice : join point가 정상적으로 완료된 후에 실행이 됩니다. 예외를 던지는 상황은 정상적인 상황에서 제외됩니다.

After throwing advice : 어떤 메소드가 예외를 던지면 실행이 됩니다.

Around advice : 메소드 호출과 같이 join point를 감싸는 Advice. 이 녀석은 advice 중에 가장 능력이 좋다. 메소드 호출 전과 후에 어떤 것을 실행할 수 있다. 또한 join point 이 후에 실행될 작업을 계속 수행할지 말지 정할 수 있다. 수행 하지 않을 때는 자신이 수행할 메소드 대신에 값을 반환하거나 예외를 던질 수 있다.

이 중에서 필요한 기능을 수행할 수 있는 가장 최소화된 능력을 발휘하는 Advice를 사용하는 것을 권장합니다. 예를 들어 어떤 메소드가 값을 반환한 이후 cache를 업데이트 하려고 할 때 Around advice를 사용할 수도 있겠지만 After returning advice를 사용합시다. 이렇게 가장 구체적인 Adivce 타입을 사용하는 것은 잠재적으로 발생할 에러를 방지 할 수 있습니다.

top

TAG advice, AOP

Write a comment.


AOP 학습 일정 1

JEDI/ToDo : 2007. 1. 4. 14:35


2주간 : Spring Reference 6장 공부
영근님과 온라인에서 발표

6. Aspect Oriented Programming with Spring
6.1. Introduction
6.1.1. AOP concepts
6.1.2. Spring AOP capabilities and goals
6.1.3. AOP Proxies in Spring
6.2. @AspectJ support
6.2.1. Enabling @AspectJ Support
6.2.2. Declaring an aspect
6.2.3. Declaring a pointcut
6.2.3.1. Supported Pointcut Designators
6.2.3.2. Combining pointcut expressions
6.2.3.3. Sharing common pointcut definitions
6.2.3.4. Examples
6.2.4. Declaring advice
6.2.4.1. Before advice
6.2.4.2. After returning advice
6.2.4.3. After throwing advice
6.2.4.4. After (finally) advice
6.2.4.5. Around advice
6.2.4.6. Advice parameters
6.2.4.7. Advice ordering
6.2.5. Introductions
6.2.6. Aspect instantiation models
6.2.7. Example
6.3. Schema-based AOP support
6.3.1. Declaring an aspect
6.3.2. Declaring a pointcut
6.3.3. Declaring advice
6.3.3.1. Before advice
6.3.3.2. After returning advice
6.3.3.3. After throwing advice
6.3.3.4. After (finally) advice
6.3.3.5. Around advice
6.3.3.6. Advice parameters
6.3.3.7. Advice ordering
6.3.4. Introductions
6.3.5. Aspect instantiation models
6.3.6. Advisors
6.3.7. Example
6.4. Choosing which AOP declaration style to use
6.4.1. Spring AOP or full AspectJ?
6.4.2. @AspectJ or XML for Spring AOP?
6.5. Mixing aspect types
6.6. Proxying mechanisms
6.6.1. Understanding AOP proxies
6.7. Programmatic creation of @AspectJ Proxies
6.8. Using AspectJ with Spring applications
6.8.1. Using AspectJ to dependency inject domain objects with Spring
6.8.1.1. Unit testing @Configurable objects
6.8.1.2. Working with multiple application contexts
6.8.2. Other Spring aspects for AspectJ
6.8.3. Configuring AspectJ aspects using Spring IoC
6.8.4. Using AspectJ Load-time weaving (LTW) with Spring applications
6.9. Further Resources
top

Write a comment.


DDD Jedi 선수작업

JEDI/ToDo : 2006. 12. 31. 00:47


ORM : http://www.agiledata.org/essays/mappingObjects.html#MapHierarchyToTable

AOP : Spring Reference 6장, 7장 정리. 하다가 모르는 것만 Aspectj in action 참조.
* Proxy 기반과 Aspect 기반의 차이점
* Spring에서 AOP 어떻게 쓰는가 (reference 참조)
* 어떻게 쓰는지, 기본 개념 등이 파악되면.. 언제 어떻게 쓰는 것이 좋은가.
* AOP를 써서 어떨 때 어떻게 좋아졌는지 보여주는 예제 소스 코드 위주로 공부.
top

  1. Favicon of http://decoder.egloos.com BlogIcon decoder 2006.12.31 03:25 PERM. MOD/DEL REPLY

    빠르시군요. 저도 AOP, ORM과 같은 것들에 대해 알아야 하니, 종종 들러서 참고하도록 하겠습니다. :)

    Favicon of http://whiteship.tistory.com/ BlogIcon 기선 2006.12.31 10:26 PERM MOD/DEL

    영회형이 길을 알려준걸 정리한 것 뿐입니다.

    대엽씨도 영회형이랑 한번 상의를 해보세요.
    아. 메신저 아이디 이메일로 보내 주시면 제가 메신저로 알려드릴꼐요. :)

    저 역시 빌드&디플로이 많이 참조 하겠습니다.

  2. Favicon of http://decoder.egloos.com BlogIcon decoder 2006.12.31 13:42 PERM. MOD/DEL REPLY

    아.. 그렇게 하면 되겠군요. :)
    제 msn아이디는 decoder@nate.com입니다.
    새해엔 남들에게 도움되는 '부지런함'을 길러봐야겠습니다.

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2007.01.01 21:52 신고 PERM MOD/DEL

    MSN 대화상대 추가 했습니다.
    이메일로 AJN 블로그 계정 보내 드리겠습니다. ;)

Write a comment.


Inversion of Control



Inversion of Control

Dependency Injection(의존성 주입)과 혼용되어 사용되는 것을 종종 보았는데 이 글을 읽어보니 어느정도 명확해 지네요. IOC가 보다 광범위한 의미이고 이 것을 표현하는 여러가지 방법이 있습니다. DI도 그중에 하나라고 하네요. 이번 장에서 말하고 있기로는 AOP와 DI가 IOC의 일부라고 합니다.

먼저 간략히 정의를 살펴보면 IOC는 braod range of techniques that allow an object to become a passive participant in the system. IOC를 사용하면 객체의 몇몇 특성이나 시점(aspect)에 대한 제어권을 프레임웍이나 환경에게 넘기게 됩니다. 그러한 제어권에는 객체의 생성이나 의존하는 객체들의 임명 등이 있습니다.

AOP

먼저 AOP를 사용하게 되는 경우를 살펴보겠습니다.

여기 보시면 주황색 부분의 코드(인증 관련 코드)가 매번 중복되어 나타나는 것을 볼 수 있습니다.
사실 인증은 메소드 본래의 작업이 아닌 부가적인 작업에 불과함에도 본래 코드보다 많은 부분을 차지 할 뿐만 아니라 계속해서 반복되어 나타나고 있습니다.

이 코드를 시스템 뒤딴으로 빼려면 Spring의 AOP(Aspect-Oriented Programming)를 사용하서 간단히 해결할 수 있습니다. Aspects are concerns of the application that apply themselves across the entire system. Aspect란 전체 시스템에서 통용되어 사용되는 에플리케이션과의 관계라고 할 수 있나요...흠; 어렵네요. 위 예제에서는 SecurityManager가 시스템에서 통용되는 aspect의 하나의 예라고 할 수 있겠네요. 그리고 통용된다는 증거로 모든 BankAccount의 모든 메소드에서 hasPermission 메소드를 호출하고 있습니다. 이런 비슷한 aspect로는 logging, auditing, transaction management가 있습니다. 이 중에 auditing은 뭔지 잘 모르겠네요.


Spring AoP는 이러한 aspect들을 runtime 때 또는 compile 때 도메인 모델(여기선 BankAccount)에 끼워넣습니다.(보통 weaving 한다고 합니다.) 이 말은 BankAccount에서 위와 같이 주황색 부분의 코드를 전부 지워도 AOP 프레임웤이 이 전과 똑같이 동작하도록 도와준다는 것입니다.

Spring은 기본적으로 proxy-based AOP(프록시 기반 AOP)를 사용합니다. 이 말은 원래 목표가 되는 객체(targer object)를 - 여기서는 BankAccount가 되겠죠- Aspect를 적용하기 위해서 Proxy로 감싸서 목표 객체 대신에 사용한다는 것입니다.  다음의 그림을 보시면 이해가 될 것입니다.

여기서 잠깐 Spring은 프록시가 아닌 컴파일 할 때 끼워넣는 AspectJ를 지원한다는 점. 그리고 이게 단순한 프록시를 사용하는 솔루션 보다 더 많은 기능을 가지고 있다고 합니다.


BankTeller가 colseOut을 호출 하면 이것은 BankAccount의 메소드를 호출하는 것이 아니라 BankAccount의 프록시를 호출하게 되고 이 프록시는 weaving된 aspect에 따라 3번 작업을 하고 그리고 본래의 작업인 4번을 BankAccount를 이용하여 처리합니다.
여기까지 정리
  • IOC는 제어권을 프레임웤에 넘기는 포괄적인 개념이다.
  • 여기서 제워권이란 새로운 객체의 생성, 트랜잭션, 보안에 대한 제어들을 이야기 한다.
  • AOP는 IOC를 실현하는 하나의 기술이다.
  • DI또한 IOC를 실현하는 하나의 기술이다.
Dependency Injection

DI는 Spring 프레임웤의 핵심 기술입니다. DI is a technique that framework use to wire together an application. 프레임웤은 에플리케이션 간의 종속성을 연결하는 작업을 하여 에플리케이션에 있는 객체 생성을 하는 코드를 제거하는 일을 합니다.

DI와 Service Locator pattern을 비교할 수 있는데.. 그 둘을 비교하기 위해 간단한 예제를 보겠습니다. 이 예제는 쇼핑카트에 있는 물품들을 계산을 하는데 DB로 부터 그 물품들의 가격을 가져와서 합산하는 프로그램입니다. 따라서 먼저 간단한 인터페이스를 하나 작성을 합니다. 이 인터페이스는 CashRegister로써 쇼핑 카트를 매개변수로 받아서 그 안에 있는 물품을 계산하는 calculateTotalPrice 메소드가 있습니다. 그리고 PriceMatrix 인터페이스에는 lookup 메소드가 있어서 원하는 물품의 가격을 반환해주는 일을 합니다.


그리고 CashRegister를 구현한 CashRegisterImpl을 봅시다.


어쩌면 이렇게 한 것이 매우 자연스럽지만 다음과 같은 세가지 중요한 문제가 있습니다.
먼저 가장 중요한 것으로 인터페이스가 아닌 특정 구현에 의존한다는 것입니다. 이 말은 H.F. Degisn Pattern 1장에 나오는 디자인 원칙이며 위 코드는 그것을 어겼습니다. 특정 구현에 의존하게 되면 왜 안좋은지에 대한 것은 위에서 확인하시기 바랍니다.
둘째 PriceMatrixImpl 객체가 CashRegisterImpl을 생성 할 때 마다 매번 생성된다는 것입니다. 이것은 문제가 있지요. 가격표는 하나만 있으면 되는데 매번 계산할 때 마다 새로운 가격표를 생성한다는 것은 자원을 낭비하는 일입니다.
마지막으로 첫번째 발생한 일에 딸려 오는 문제로써 테스트하기가 힘들다는 것입니다. CashRegister를 테스트하기 위해서는 지금 PriceMatrixImpl까지 제대로 구현으르 해야 테스트가 가능합니다. 그리고 단위 테스트는 아예 할 수가 없는 상황이네요.

그럼 PriceMatrix없이 테스트가 가능하기나 하냔 말인가가 궁금한데요. 저도 잘 모르는 부분인데 Mock이라는 기술을 사용하면 단위 테스트가 가능하다고 합니다.

Service Locator를 사용해 봅시다.

Service Locator Pattern은 객체를 생성하여 그 레퍼런스를 얻어내는 과정을 숨기는 것을 말합니다. 클라이언트를 객체가 언제, 어디서 어떻게 생성되는지 모르도록 하는 패턴입니다. 클라이언트를 보호하고 코드 중복을 줄이기 위해서 이 패턴이 만들어졌다고 합니다. 보통 static 메소드를 사용하여 요구된 객체에 대한 하나의 객체를 반환해 줍니다. (싱글턴 패턴하고 다른게 뭐죠? 첨에는 static 팩토리인가.. 생각했다가 오직 하나의 클래스에 대한 하나의 객체만 리턴 해주면 이거 싱글턴 아닌가.. 하는 생각이 들었습니다.)


이렇게 함으로써 첫번째 문제(특정 구현에 의존하던 문제)와 두번째 문제(매번 새로운 객체를 생성하던 문제)가 해결되었습니다. 하지만 세번째 단위 테스트를 하려면 Mock 객체를 사용해야 하는데 Mock객체를 끼워넣을 방법이 없습니다. 왜내면 저 위의 주황색 부분이 test할 때는 Mock 객체를 넘겨주고 실제 사용할 때는 PriceMatrix객체를 주도록 바꾸기가 어렵기 때문입니다. 이런것을 효율적으로 하려면 클라이언트 코드에서 자원을 가져오거나 생성하는 활동에 전혀 참여하면 안됩니다. 그냥 자원이 클라이언트에 주어져야 합니다.

Dependency Injection을 사용해 봅시다.

Service Locator를 사용하는 대신에 프레임웤이 PriceMatrix type 객체의 레퍼런스를 CashRegisterImpl에 제공해 줍니다.  객체 생성과 객체 연결(location)에 대한 책임이 클래스에서 프레임웤으로 뒤집어졌습니다. 이러한 것을 DI라고 하며 두 가지 방법이 흔히 사용됩니다.

Spring AOP의 도움을 받는 method-based injection이라고 불리는 세번째 방법도 있으나 복잡하고 잘 쓰이질 않아서 여기서 다루진 않는답니다.

처음으로 볼 DI의 한 종류로는 constructor-based injection이 있습니다. 이 것은 객체가 생성될 때 종속성을 주입하는 방법입니다.


이렇게 하면 된거죠. 하지만 이 클래스는 Hollywood Principle을 따르고 있는데요. 할리우드 원칙이란 "내가 전화할테니 전화하지 마!"라는 원칙입니다. 다시 이 경우에 대입해 본다면 "내가 줄테니 자원을 달라고 요청하지마!" 라고 할 수 있겠습니다.

다음은 Setter-based injection입니다.


PriceMatrix type의 객체 생성 시기가 좀더 유연해 졌습니다. 생성자 기반과 세터 기반 중에 어떤 것을 사용할 지는 사용자의 선택입니다. 물론 어떤 경우를 선택하느냐에 따라 실제 종속성을 주입할 때 따르게 되는 지침에 해당하는 XML 파일의 내용이 약간 바뀔 것입니다.
이 것은 생성자 기반 종속성 주입 시에 사용할 XML 설정 파일의 일부이며
이 것은 세터 기반 종속성 주입 시에 사용할 XML 설정 파일의 일부입니다.

첫번째 문제-특정 구현에 의존했었던-는 해결된 듯 합니다.
두번째 문제-매번 새로운 객체를 생성했던-도 역시 bean이 기본적으로 싱클턴 객체로 생성되기 때문에 해결 된 듯합니다.
그럼 남은것은 세번째 문제-단위 테스트를 할 수 없었던-것인데요.
이렇게 하면 Service Locator에서 해결 못했던 Mock을 사용한 단위 test를 어떻게 할 수 있을까요?

처음 본거라 저도 잘 모르겠지만 다음과 같이 Mock을 사용한다고 합니다.

여기까지 정리하면..
  • DI는 종속성을 필요로 하는 코드 없이 여러 클래스들을 묶는데 사용하는 기술입니다.
  • 클라이언트는 프레임웤에게 종속성의 생명주기 관리를 넘겼습니다.
  • 이렇게 함으로써 클라이언트는 테스트하기 용이해 집니다.

'Spring MVC > 2장 Spring 기본요소' 카테고리의 다른 글

Spring ApplicationContexts  (0) 2006.10.06
Inversion of Control  (4) 2006.10.06
top

  1. Favicon of http://www.anfamily.net/mcsong BlogIcon mcsong 2007.03.13 17:50 PERM. MOD/DEL REPLY

    요즘에 슬슬 프레임웍에 관심이 땡겨서 보고 있는데요..
    님 글의 Defendency Injection -> Dependency Injection 아닌가요??
    ㅎㅎ

    Favicon of https://whiteship.tistory.com BlogIcon 기선 2007.03.13 18:07 신고 PERM MOD/DEL

    허걱..이런ㅋㅋ
    감사합니다.

  2. SGcom 2008.09.18 05:33 PERM. MOD/DEL REPLY

    초보자로써 이해가지 않는게 priceMatrix를 가지고 설명하시다가 스프링 설정에가서는 왜 AddressServiceImpl을 사용하신 거죠??둘이 연관이 있나요??

    Favicon of http://whiteship.tistory.com BlogIcon 기선 2008.09.18 08:30 PERM MOD/DEL

    2년 전에 작성한 글이네요. 흠..Spring MVC 저자가 그렇게 설명하고 있습니다. 예제가 달라졌지만, 저자가 설명하는 내용을 이해못할 정도는 아닌 듯 합니다. :)

Write a comment.