AspectJ와의 연동을 고려한다면, 포인트컷을 최소화 해야합니다.

무슨 이야기냐면, 최소 권한 원칙인가… 그런거랑 비슷한겁니다.

바로 예제를 보면서 살펴보죠.

@Aspect
public class HibernateExceptionToDataAccessException {

    @Pointcut(“@within(org.springframework.stereotype.Repository)”)
    public void accountHibernateExceptionInDao(){}

    @AfterThrowing(pointcut=”accountHibernateExceptionInDao()”, throwing=”e”)
    public void translateHibernateException(HibernateException e){
        throw SessionFactoryUtils.convertHibernateAccessException(e);
    }

}

이 애스팩트는 하이버네이트 예외를 스프링의 DataAccessException으로 변환해주는 애스팩트입니다. 이 녀석은 하이버네이트로 DAO 만드는 여러 방법 중에 가장 깔끔한 방법을 사용할 때 쓰면 좋고 안 써도 별로 상관없는(하이버네이트 버전이 올라가면서 하이버네이트 예외도 uncatched exception으로 바꼈으며 계층 구조도 세밀하게 나눠뒀기 때문입니다.) 그런 애스팩트입니다. 그래도, 버전 올리기 힘든 하이버 예전 버전을 사용하는 라이브러리를 사용해야 한다면 유용하겠죠.

어쨋든, 본론으로 돌아가서..

저렇게 만들어둔 애스팩트에 문제점이 보이나요? 저도 방금전까진 몰랐습니다. 일단, 저 애스팩트의 포인트컷은 이해가 가시죠? @Repository 애노테이션을 가지고 있는 클래스의 모든 조인포인트를 나타낸 겁니다.

문제는 바로 이 조인포인트.. 이게 핵심입니다. 스프링에서는 메소드 실행 조인포인트만 사용하기 때문에, 저 애스팩트를 스프링 AOP에서 사용할 땐, 원하던 메소드에만 적용이 될 겁니다. 하지만, 만약 저 애스팩트를 AspectJ와 연동해서 사용한다면? 어떤 일이 벌어질까요?

사용자 삽입 이미지
캬오.. 43개??? 말도 안돼. 내가 테스트 할려고 만든 DAO가 몇개나 된다고.. 그 안에 메소드도 거의 한 두 개밖엔 안만들었는데.. 왠 43개…. 바로 크로스 레퍼런스 뷰를 열고 확인해봤습니다.

사용자 삽입 이미지
캬오~~~~ 마이 미스테이크… 처방이 필요합니다. 처방은 간단하기 때문에 비밀! 캬캬캬.(이번주 KSUG 세미나에서 공개하도록 하죠.) 처방후에는..

사용자 삽입 이미지
이렇게 AspectJ에서도 메소드 실행 조인포인트에만 걸 수 있습니다. 음하하하..

개발에 필요한 AOP 뭐가 있을까?

1. 간단한 메소드 성능 검사

 개발 도중 특히 DB에 다량의 데이터를 넣고 빼는 등의 배치 작업에 대해서 시간을 측정해보고 쿼리를 개선하는 작업은 매우 의미가 있을 겁니다. 그럴 때 귀찮게 매번 해당 메소드 처음과 끝에 System.currentTimeMillis();를 쓰거나, 스프링이 제공하는 StopWatch 코드를 집어넣고 빼긴 뭐 합니다. 그런식으로 테스트 해보고 싶은 메소드가 여러 개일 때도 귀찮겠죠?

2. 트랜잭션 처리

트랜잭션 처리는 거의 필수라는 생각이 듭니다. 저야.. 여태까지 스프링의 도움으로 아무런 어려움없이 간단하게 트랜잭션 기능을 사용하고 있지만, 이걸 스프링 없이 사용하려고 해보니 코딩 하기가 싫어졌습니다. 보기 싫은 try-catch 코드는 계속 늘어나고, 핵심 로직은 정글 속에 숨어버리니 말이죠.

3. 예외 변환

스프링에는 DataAccessException이라는 매우 잘 정의되어 있는 예외 계층 구조가 있습니다. 예전 하이버네이트 예외들은 몇 개 없었고 그나마도 Uncatched Exception이 아니였습니다. 이렇게 구조가 별로 안 좋은 예외들이 발생했을 때, 그걸 잡아서 잘 정의되어 있는 예외 계층 구조로 변환해서 다시 던지는 애스팩트는 제 3의 프레임워크를 사용할 때, 본인의 프레임워크나 애플리케이션에서 별도의 예외 계층 구조로 변환하고 싶을 때 유용합니다.

4. 아키텍처 검증

이것에 관련된 내용과 애스팩트는 어젯 밤에 공개했습니다. 유용하겠죠?

5. 기타

하이버네이트와 JDBC를 같이 사용할 때, DB 동기화 문제 해결.
– 멀티쓰레드 Safety 관려하여 롹을 가지고 수행해야 하는 메소드들에 일괄적으로 메소드 수행 전에 롹을 가지게 하고, 메소드 실행 후에롹을 반환하는 애스팩트
– 데드롹 등으로 인해, PessimisticLockingFailureException 이런 예외를 만났을 떄 재시도를 하는 애스팩트.
– 로깅, 인증, 권환, …

찾아보니, 유용한 것들이 많이 있었습니다. 물론 이밖에도 상당히 여러 경우에 AOP를 활용할 수 있을 겁니다. 단지, 익숙하지 않다보니.. 잘 안 쓰게 되는데, 이번 주 주말 KSUG 세미나 마지막 발표를 통해서 어느 정도 AOP와 가까워지는 시간이 되길 바랍니다. 이번 세미나에서 위에 나열 한 것 중에 절반 정도를 살펴보겠습니다.

나이쓰~!!! 계층형 아키텍처 검증 용 Aspect

@Aspect
public class SystemArchitecture {

    @Pointcut(“execution(* org.opensprout.dao..*(..))”)
    public void executeDao(){}
    
    @Pointcut(“call(* org.opensprout.service..*(..))”)
    public void callToService(){}
    
    @Before(“cflowbelow(executeDao()) && callToService()”)
    public void checkDao(JoinPoint jp){
        System.out.println(“daoToService architechure checking”);
        throw new RuntimeException(“Dao can’t call Service’s method.”);
    }
    
}

뭐하는 녀석이냐면, DAO에서 Service에 있는 메소드 호출을 하지 못하게하는.. 그런 애스팩트입니다. 이걸 응용하면, 개발자 100여명에 제각각 코딩 실력일 경우 컨트롤러에서 DAO를 직접 호출한다던가, 서비스 계층에서 컨트롤러에 있는 메소드를 사용한다던가 하는 어처구니 없는 코드를 찾아낼 수 있습니다.

흐아~ 이 녀석 어떻게 구현할지 생각해내느라, PPT 만들다가 고민하고, 고민하다가 집에 맥주 사들고와서 코딩해보고 테스트까지 완료, call이랑 cflowbelow 포인트컷을 아직 스프링 @AOP에서 지원하지 않기 때문에, AspectJ를 써야 하는데, 클래식 스프링 AOP를 사용하면 구현 가능합니다.

CFlow뭐시기Pointcut 클래스를 사용하면 되고, call대신에 method execution 포인트컷을 사용해도 무관합니다. 그 구현은 자바 5 미만 버전을 사용하시는 분에게 맡기겠습니다. 전 자바 5 미만이 싫어효. ^^;

잠잘 시간 전에 해내서 정말 기쁩니다. 아~ 맘편히 잘 수 있겠다. 휴우~~~

ps: 헤어진 여친 나오는 꿈은 제발 그만, 나 정말 꿈에서 깨기 싫었다. 나타나지 말아줘. 마이 뉴 여친. 원더걸스 나와라~ 원더걸스 나와라~ 원더걸스 나와라~

AOP를 설명하는 그림 두 장

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

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

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

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

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

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

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

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

소스 코드 보기

[#M_ more.. | less.. |

// Human.java
public interface Human {    
     
public void sayName();

}


// Keesun.java

public class Keesun implements Human {

       public void sayName() {

             System.out.println(저는 ~~선입니다.”);

       }

}


//MannerAOP.java

@Aspect

public class MannerAOP {

 

       @Pointcut(“execution(public * Human.sayName(..))”)

       public void greeting() {

       }

 

       @Before(“greeting()”)

       public void hi() {

             System.out.println(만나서 ~~습니다.”);

       }

 

       @AfterReturning(“greeting()”)

       public void doBeforeOne() {

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

       }

}


//aopAppContext.xml

<?xml version=“1.0” encoding=“UTF-8”?>

<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=“firstSpringAOP.Keesun” />

 

       <aop:aspectj-autoproxy />

 

       <!– this is the actual advice itself –>

       <bean id=“mannerAOP” class=“firstSpringAOP.MannerAOP” />

</beans>


// TestFirstAOP.java

public class TestFirstAOP {

       public static void main(String[] args) {

 

             BeanFactory bf = new ClassPathXmlApplicationContext(

                           “firstSpringAOP/aopAppContext.xml”);

             Human human = (Human) bf.getBean(“keesun”);

             human.sayName();

       }

}


_M#]실행 결과

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

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

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


bl162.mp3bl163.zip