Whiteship's Note

'AOP'에 해당되는 글 40건

  1. 2009.06.12 [AspectJ] LTW시 메이븐에 VM 옵션주기
  2. 2009.06.12 [AspectJ] 톰캣 6.X에 LTW(load time weaving) 설정하기
  3. 2009.06.08 [AspectJ] Extension and Implementation
  4. 2009.06.08 [AspectJ] privileged aspect (4)
  5. 2008.10.21 AspectJ의 @DeclareError를 사용해서 컴파일 시점에 아키텍처 에러 검증하자. (6)
  6. 2008.10.08 AspectJ와의 연동을 고려한다면, 포인트컷을 최소화 해야합니다. (2)
  7. 2008.10.06 개발에 필요한 AOP 뭐가 있을까? (2)
  8. 2008.10.05 나이쓰~!!! 계층형 아키텍처 검증 용 Aspect (8)
  9. 2008.10.04 AOP를 설명하는 그림 두 장 (2)
  10. 2008.01.08 4. @AspectJ 사용하는 초간단 AOP 예제 (13)
  11. 2007.09.07 AOP Design 이슈
  12. 2007.08.22 AspectJ In Action 3장
  13. 2007.04.01 BeanNameAutoProxyCreator 사용 예
  14. 2007.04.01 Autoproxy
  15. 2007.03.30 Spring AOP(old) ProxyFactoryBean 불편한 점
  16. 2007.03.30 기선 씨네마 :: Pointcut
  17. 2007.03.30 기선 씨네마 :: Advice
  18. 2007.03.30 기선 씨네마 :: 티켓 만들어 주기
  19. 2007.03.30 Spring AOP 공부를 위한 예제 - 기선 씨네마
  20. 2007.03.28 Spring AOP(old) Pointcut Implementation
  21. 2007.03.28 Spring AOP(old) Advisor
  22. 2007.03.28 Spring AOP(old) Pointcut
  23. 2007.03.28 Spring AOP(old) Advice
  24. 2007.03.28 Spring AOP(old) 특징
  25. 2007.03.27 3월달 마소 AOP 기사 정리
  26. 2007.02.15 Eclipse에서 AspectJ 개발 동영상입니다.
  27. 2007.02.04 AOP: Radical Research in Modularity (4)
  28. 2007.01.17 12. Advice parameters 1 (2)
  29. 2007.01.16 11. within 포인트컷 & this 포인트컷 사용하기
  30. 2007.01.16 10. execution 포인트컷 사용하기

[AspectJ] LTW시 메이븐에 VM 옵션주기

AOP : 2009.06.12 19:59


스프링 @Configurable을 이용하려면 정적인 컴파일 시점 위빙으로는 안 됩니다. 객체가 필요해서 해당 클래스를 처음 클래스로더가 읽어갈 때.. 그 때 aop.xml 정보를 참조해서 위빙을 해야 합니다. 그게 바로 LTW죠.

-javaagent:/path/to/spring-agent.jar

그러려면 이런 옵션을 VM 인자로 넘겨줘야 합니다. 이클립스에서 JUnit 테스트를 실행할 때도 예외는 아닙니다.


이런식으로 모든 테스트에 인자를 줘야 하는데.. 여간 귀찮은 작업이 아닙니다. 프로젝트 별로 VM 인자를 설정하는 방법이 없나. 모르겠습니다.

메이븐으로 빌드를 하면 당연히 실패하겠죠. 그래서 메이븐에도 설정해줘야합니다. test 할 때 위빙 옵션을 다음과 같이 줄 수 있습니다.

            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.4.2</version>
                <configuration>
                    <argLine>-javaagent:weaving/spring-agent.jar</argLine>
                </configuration>
            </plugin>

이클립스 + 콘솔창 한개는 기본으로 들고 개발을 해야겠습니다. 안그래도 git와 mvn war:inplace 때문에 거의 항상 콘솔창 하나를 띄워서 같이 작업하는데, mvn clean test도 애용하게 생겼네요.
top


[AspectJ] 톰캣 6.X에 LTW(load time weaving) 설정하기

AOP : 2009.06.12 19:47


1. 톰캣 홈/lib 폴더에 spring-tomcat-weaver.jar를 복사해서 넣어둡니다.


2.5.6 버전 배포할 때 제공된 녀석인데, 3.0 M3에서 확인해본 결과 잘 동작하더군요.

2. server.xml에서 context 정보를 수정해줍니다.

<Context docBase="C:\workspace\koma-ddd\webapp" path="/" reloadable="false">
          <Loader loaderClass="org.springframework.instrument.classloading.tomcat.TomcatInstrumentableClassLoader"/>
</Context>

Context 내부에서 위와 같이 loader 엘리먼트를 추가해주면 됩니다.

3. applicationContext.xml에 다음 엘리먼트를 추가합니다.

    <context:load-time-weaver />

끝입니다. @_@ 참.. 쉽죠~


top


[AspectJ] Extension and Implementation

AOP : 2009.06.08 20:16


http://www.eclipse.org/aspectj/doc/released/progguide/semantics-declare.html#extension-and-implementation

    declare parents: EmpDao extends GenericDao<Emp, EmpParams>;
    declare parents: EmpDaoImpl extends HibernateGenericDao<Emp, EmpParams>;
    declare @type: EmpDaoImpl: @org.springframework.stereotype.Repository;

EmpDao 클래스가 GenericDao 클래스를 상속 받도록 설정.
EmpDaoImpl 클래스가 HibernateGenericDao 클래스를 상속 받도록 설정.
EmpDaoImpl 클래스에 @Repository 애노테이션 추가.

문법이 복잡해 보였는데 막상 사용해보니 간단 간단 하네요.

public interface EmpDao {

}

public class EmpDaoImpl implements EmpDao {

}

이런 기초적인 코드만 존재하지만..

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"/applicationContext.xml", "/applicationContext-datasource.xml"})
@Transactional
public class EmpDaoImplTest {

    @Autowired
    EmpDaoImpl daoImpl;

    @Test
    public void daoInterface() throws Exception {
        assertNotNull(daoImpl);
        daoImpl = new EmpDaoImpl();
        GenericDao<Emp, EmpParams> gdao = daoImpl;
        HibernateGenericDao<Emp, EmpParams> hgdao = daoImpl;
    }

    @Test
    public void crud() throws Exception {
        Emp emp = new Emp();
        daoImpl.add(emp);
        daoImpl.flush();
        assertEquals(1, daoImpl.getAll().size());
    }

}

이런 테스트를 돌릴 수 있다는거...



top


[AspectJ] privileged aspect

AOP : 2009.06.08 17:24


public class Emp {

    private String name;

    private String email;

}

이런 클래스가 있습니다. 이게 전부입니다.

public class EmpTest {

    @Test
    public void javaBean() throws Exception {
        Emp emp = new Emp();
        emp.setName("keesun");
        assertEquals("keesun", emp.getName());
        emp.setEmail("keesun@email.com");
    }

}

이런 테스트가 돌아갈까요? 훗.. 그럴리가요. 있지도 않은 메서드(게터, 세터)를 마구 썼는데 될리가 없죠. 그러나..  잘 돌아갑니다.


어떻게 된걸까요? privileged aspect를 사용하면 타겟의 private 또는 protected 멤버에도 접근할 수 있습니다.

http://www.eclipse.org/aspectj/doc/released/progguide/semantics-aspects.html#aspect-declaration

스프링 AOP로 이런 일을 하려면 Introduction을 사용 해야겠는데.. 그게 참.. 그리 쉽지 않았던 기억이 납니다. 하지만 AspectJ로는 간단하네요~

privileged aspect EmpAspect {

    //JavaBean
    public String smdis.model.Emp.getName() {
        return this.name;
    }

    public void smdis.model.Emp.setName(String name) {
        this.name = name;
    }

    public String smdis.model.Emp.getEmail() {
        return this.email;
    }

    public void smdis.model.Emp.setEmail(String email) {
        this.email = email;
    }

}

이렇게 추가할 메서드를 넣어주고 마치 자기가 가지고 있는 변수처럼 사용하면 됩니다.
top


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


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

AOP : 2008.10.08 16:37


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

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

@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에서도 메소드 실행 조인포인트에만 걸 수 있습니다. 음하하하..
top


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

AOP : 2008.10.06 17:22


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

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

2. 트랜잭션 처리

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

3. 예외 변환

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

4. 아키텍처 검증

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

5. 기타

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

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


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

AOP : 2008.10.05 23:57


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

top


AOP를 설명하는 그림 두 장

AOP : 2008.10.04 18:24


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

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

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

TAG AOP

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

AOP : 2008.01.08 17:18


사용자 삽입 이미지

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

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

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

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

소스 코드 보기

more..

실행 결과
만나서 반~갑~습니다.
저는 백~기~선입니다.
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

AOP Design 이슈

AOP : 2007.09.07 19:18


참조 : J2EE Development without EJB 8장 207쪽

Should We Intercept Fields?(필드 Joinpoint를 사용해야 되나?)

객체 지향의 Encapsulation을 깨트리게 되기 때문에 Method Joinpoint로 해결하는 것이 좋겠다.

Too Many Asepcts?(너무 많은 Aspect를 적용해서 메소드를 호출 할 때 뭐가 실행될지 알 수가 없다.)

Tool의 활용이 이 문제를 어느정도 해결해 줄 수 있지만, 일단은 그렇게 많은 Apset를 적용한 프로젝트도 없을 뿐더러, 프로그램 구조를 간단하게 가져가면 해결할 수 있을 것이다.

Orthogonality(직교성)

여러 Aspect가 한 곳에 적용될 때 Aspect 끼리 서로 영향을 끼치는 경우 예측 불가능한 상황이 발생할 수 있을 텐데 이런 문제는 어떻게 해결할 수 있을까?

대부분의 AOP 프레임워크에는 적용되는 Advice의 순서를 정할 수 있다.

Testing Application Using AOP

AOP를 적용하면 왠지 테스트가 어려울 것 같지만, 정 반대로 모듈화를 통해 테스트가 더 용이해 집니다. 트랜잭션 코드를 Aspect로 빼버리면 단위 테스트 할 때 트랜잭션 관련된 테스트 코드를 작성하지 않아도 되겠죠. 그리고 통합 테스트라고 해서 별반 다를 것은 없습니다.

Debugging

??? 흠.. Vertical Slice라는 용어가 나오는데  뭔지 모르겠습니다.

Won't AOP Seriously Affect Perfomance?

AspectJ가 빠르긴 한데 다른 AOP 구현체들에 비해 큰 차이가 나는 것은 아니다. 리플렉션과 객체 생성으로 성능 문제가 생길 수 있지만 자바 리플렉션과 GC의 기능이 향상되고 있다.

성능은 AOP가 적용되는 Granularity와 관련이 있다. 매우 세부적인 곳에 적용하는 Aspect를 많이 사용하면 문제를 발생시킬 수 있지만 대부분 EJB method interception 보다는 성능이 좋을 것이다.
top


AspectJ In Action 3장

AOP : 2007.08.22 15:34


Spring AOP도 Spring 2.0 부터는 AspectJ 의 포인트 컷 표현식을 사용 할 수 있게 되었습니다. AspectJ 문법에 대한 Eclipse 사이트의 온라인 문서도 있지만 AspectJ In Action 3장에도 자세히 나와있습니다.

운 좋게도 java.net에서 AspectJ In Action 3장을 다운로드 할 수 있게 해두었군요.
다음 KSUG 세미나 대비로 살짝 살펴보시는 것이 좋겠습니다.

http://today.java.net/pub/a/today/2003/12/26/ch3AspectJSyntaxBasics.html

'AOP' 카테고리의 다른 글

개발에 필요한 AOP 뭐가 있을까?  (2) 2008.10.06
나이쓰~!!! 계층형 아키텍처 검증 용 Aspect  (8) 2008.10.05
AOP를 설명하는 그림 두 장  (2) 2008.10.04
4. @AspectJ 사용하는 초간단 AOP 예제  (13) 2008.01.08
AOP Design 이슈  (0) 2007.09.07
AspectJ In Action 3장  (0) 2007.08.22
BeanNameAutoProxyCreator 사용 예  (0) 2007.04.01
Autoproxy  (0) 2007.04.01
Spring AOP(old) ProxyFactoryBean 불편한 점  (0) 2007.03.30
기선 씨네마 :: Pointcut  (0) 2007.03.30
기선 씨네마 :: Advice  (0) 2007.03.30
top


BeanNameAutoProxyCreator 사용 예

AOP : 2007.04.01 11:06


    @Test
    public void anotherClassesJoinPoint() {
        keesun.getAge();
        movie.getName();
        hein.getCard().getPoint();
    }

Customer, Movie, MemberShipCard 객체에 있는 getter들이 호출 될 때 어떤 일을 추가하고 싶을 때 각각의 ProxyFactoryBean을 만드는 대신 BeanNameAutoProxyCreator를 사용하여 advisor가 적용될 bean들을 등록해 두면 자동으로 해당 bean의 프록시를 만들어 사용하게 됩니다.

먼저 간단한 before Advice를 하나 만들고 bean으로 등록 합니다.
public class GetterAdvice implements MethodBeforeAdvice {

    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("getter joined " + target.getClass().getName() + " class " + method.getName());
    }
}

<bean id="getter" class="aop.oldStyle.advice.GetterAdvice" />

그리고 이제 BeanNameAutoProxyCreator를 bean으로 등록합니다.
    <!-- BeanNameAutoProxyCreator -->
    <bean id="getterAutoProxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator" >
        <property name="beanNames">
            <list>
                <value>혜인</value>
                <value>기선</value>
                <value>KCcard</value>
                <value>movie</value>
            </list>
        </property>
        <property name="interceptorNames" value="getter" />
    </bean>

beanNames속성에는 advice가 적용될 bean들을 적어 줍니다. 여기에서도 역시 와일드 카드를 사용하여 하나의 문장으로 여러 bean을 나타낼 수 있습니다.

테스트를 실행하면 콘솔창에서 다음과 같은 메시지를 확인할 수 있습니다.
getter joined aop.oldStyle.domain.Customer class getAge
getter joined aop.oldStyle.domain.Movie class getName
getter joined aop.oldStyle.domain.Customer class getCard
getter joined aop.oldStyle.domain.MemberShipCard class getPoint


top


Autoproxy

AOP : 2007.04.01 10:07


이전에 잠시 ProxyFactoryBean을 사용하여 일일히 Proxy 객체를 만드는 것이 얼마나 피곤할 수 있는지 언급을 했었습니다.

aspect가 적용 될 부분이 객체 단위로 나눠 진다면 저렇게 하는게 편할 수도 있겠지만 그냥 타겟 객체를 멤버로 가지고 타겟 객체의 인터페이스를 구현하면서 타겟 객체의 메소드를 활욜하여 원하는 대로 구현하면 되니까요. 굳이 복잡하게 프록시 객체니 AOP니 사용할 필요가 없겠죠.

하지만 여러 객체을 관통하여 그 객체의 곳곳에 침투 해야 하는 Advice라면 어떻게 해야 할까요? 그 여러 객체에 해당하는 모든 프록시 객체를 만들어 줘야 하겠죠. Spring AOP는 프록시 객체를 사용하기 때문에 그렇게 될 것입니다.

이럴 때 Spring IoC container에 AbstractAutoProxyCreator 를 등록해 두면 컨테이너가 알아서 프록시들을 자동으로 생성해 주게 됩니다. 이 기능을 사용하면 굉장히 편하겠죠.

다음은 AbstractAutoProxyCreator를 상속한 클래스들 입니다.

BeanNameAutoProxyCreator, AbstractAdvisorAutoProxyCreator, AspectJAwareAdvisorAutoProxyCreator, DefaultAdvisorAutoProxyCreator, AnnotationAwareAspectJAutoProxyCreator

BeanNameAutoProxyCreator 사용 예

인터페이스를 구현하지 않은 객체들의 프록시도 필요할 수 있기 때문에 CGLIB jar파일을 필요로 합니다.

BeanPostProcessor를 사용하여 프록시 객체의 대상이 될 객체들을 찾아내서 그 객체들이 호출되기 전에 인터셉터들(어드바이스)을 끼워넣습니다.

'AOP' 카테고리의 다른 글

AOP를 설명하는 그림 두 장  (2) 2008.10.04
4. @AspectJ 사용하는 초간단 AOP 예제  (13) 2008.01.08
AOP Design 이슈  (0) 2007.09.07
AspectJ In Action 3장  (0) 2007.08.22
BeanNameAutoProxyCreator 사용 예  (0) 2007.04.01
Autoproxy  (0) 2007.04.01
Spring AOP(old) ProxyFactoryBean 불편한 점  (0) 2007.03.30
기선 씨네마 :: Pointcut  (0) 2007.03.30
기선 씨네마 :: Advice  (0) 2007.03.30
기선 씨네마 :: 티켓 만들어 주기  (0) 2007.03.30
Spring AOP 공부를 위한 예제 - 기선 씨네마  (0) 2007.03.30
top


Spring AOP(old) ProxyFactoryBean 불편한 점

AOP : 2007.03.30 15:53


포인트컷이 매우 제한적입니다. 메소드 실행시점 뿐이여서 제한적이라는 것이 아니라 대상이 되는 메소드들이 ProxyFactoryBean의 Target 객체 하나 안에 들어있는 것들로 제한적이라는 것입니다.

즉 다섯개의 Service 클래스가 있고 각각의 클래스에 있는 특정 메소드에 공통적으로 어떤 작업을 추가하고 싶을 때..

Advice는 하나면 됩니다.
포인트컷도 하나면 되겠죠.
이 두 개를 묶어서 하나의 Advisor로 만들면 지금 까지 bean 두 개면 충분합니다.
하지만 ProxyFactoryBean 다섯개가 필요합니다. -_-;;

이럴땐 DefaultAdvisorAutoProxyCreator 를 사용하면 간단해 지는군요~

top


기선 씨네마 :: Pointcut

AOP : 2007.03.30 14:01


영화관에서 표를 팔 때(sellTicket)만 welcome과 thankyou Advice를 적용하려면 이전에 살펴봤던 NameMathMethodPointcut이나 NameMathMethodPointcutAdvisor를 이용하면 됩니다.

사용자 삽입 이미지
이렇게 Advisor를 만들면서 pointcut을 정의해줘도 되고, Pointcut만 따로 만든 다음에 DefaultPointcutAdvisor로 합쳐도 됩니다.

사용자 삽입 이미지
이번에는 포인트 컷을 따로 만들고 DefaultPointcutAdvisor를 사용해서 advice와 pointcut을 묶고 그것을 ProxyFactoryBean에 주입시켰습니다.

둘 다 결과는 원하던데로 sellTicket() 메소드에만 welcome, thank Advice가 적용됩니다.


'AOP' 카테고리의 다른 글

AOP Design 이슈  (0) 2007.09.07
AspectJ In Action 3장  (0) 2007.08.22
BeanNameAutoProxyCreator 사용 예  (0) 2007.04.01
Autoproxy  (0) 2007.04.01
Spring AOP(old) ProxyFactoryBean 불편한 점  (0) 2007.03.30
기선 씨네마 :: Pointcut  (0) 2007.03.30
기선 씨네마 :: Advice  (0) 2007.03.30
기선 씨네마 :: 티켓 만들어 주기  (0) 2007.03.30
Spring AOP 공부를 위한 예제 - 기선 씨네마  (0) 2007.03.30
Spring AOP(old) Pointcut Implementation  (0) 2007.03.28
Spring AOP(old) Advisor  (0) 2007.03.28
top


기선 씨네마 :: Advice

AOP : 2007.03.30 13:01


만드는 방법은 이전에도 살짝 살펴봤지만 소스는 아래와 같습니다.
public class WelcomeAdvice implements MethodBeforeAdvice {

    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("어떤 영화를 보시겠습니까?");
    }

}

public class ThankYouAdvice implements AfterReturningAdvice {

    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("감사합니다.");
    }

}

Advice만 만든 상태에서 이걸 ProxyFactoryBean에 주입시킵니다.
    <!-- Advice -->
    <bean id="welcome" class="aop.oldStyle.advice.WelcomeAdvice" />
    <bean id="thanks" class="aop.oldStyle.advice.ThankYouAdvice" />

    <!-- AOP cinema -->
    <bean id="AOP씨네마" class="org.springframework.aop.framework.ProxyFactoryBean" >
        <property name="proxyInterfaces" value="aop.oldStyle.domain.Cinema" />
        <property name="interceptorNames">
            <list>
                <value>welcome</value>
                <value>thanks</value>
            </list>
        </property>
        <property name="target" ref="기선씨네마" />
    </bean>

이제 테스트를 해봅니다.
    @Test
    public void aopKeesunCinema() {
        hein.buyTicket(aopCinema, movie);
    }

당연히 원한대로의 결과가 나옵니다.
어떤 영화를 보시겠습니까?
감사합니다.

그럼 ProxyFactoryBean에 지정한 인터페이스의 다른 메소드들을 호출하면 어떻게 될까요?
    @Test
    public void onlyAdviceTest() {
        aopCinema.checkTicket(hein, movie);
        aopCinema.giveMemberShipCard(hein);
        aopCinema.playMovie(movie);
        aopCinema.sellTicket(movie, new Date());
    }

전혀.. 원하던 결과가 아니게 됩니다.
어떤 영화를 보시겠습니까?
감사합니다.
어떤 영화를 보시겠습니까?
감사합니다.
어떤 영화를 보시겠습니까?
공공의적상영합니다.
감사합니다.
어떤 영화를 보시겠습니까?
감사합니다.

ProxyFactoryBean에는 Advice도 등록할 수 있고 포인트컷은 해당 인터페이스에 지정한 모든 메소드가 라는 걸 확인 할 수 있습니다.

이래서 포인트컷으로 원하는 곳에만 Advice가 적용될 수 있도록 지정한뒤, 그것을 Advice와 뭉쳐서 Advisor로 등록하고 그것을 Advice를 등록한 위치(interceptorNames)에 넣어 두면 원하는 곳에만 원하는 일을 추가할 수 있게 되겠습니다.

'AOP' 카테고리의 다른 글

AspectJ In Action 3장  (0) 2007.08.22
BeanNameAutoProxyCreator 사용 예  (0) 2007.04.01
Autoproxy  (0) 2007.04.01
Spring AOP(old) ProxyFactoryBean 불편한 점  (0) 2007.03.30
기선 씨네마 :: Pointcut  (0) 2007.03.30
기선 씨네마 :: Advice  (0) 2007.03.30
기선 씨네마 :: 티켓 만들어 주기  (0) 2007.03.30
Spring AOP 공부를 위한 예제 - 기선 씨네마  (0) 2007.03.30
Spring AOP(old) Pointcut Implementation  (0) 2007.03.28
Spring AOP(old) Advisor  (0) 2007.03.28
Spring AOP(old) Pointcut  (0) 2007.03.28
top


기선 씨네마 :: 티켓 만들어 주기

AOP : 2007.03.30 12:30


Cinema에서 티켓을 팝니다.(sellTicket) 그럼 그걸 고객이 사면 되죠.(buyTicket). 반대로 고객이 영화를 보고 싶으면 영화표를 사야되고 영화표를 사려면 영화관에서 영화표를 파는 사람으로 부터 사야하죠.

사용자 삽입 이미지
문제는 이전에도 살펴봤지만 영화관은 하나여야 하고(singleton) 영화표는 여러개(prototype)여야 하는 거죠. 영화표에는 좌석, 영화, 언제 하는 건지가 적혀있죠.

그래서 이전에 써먹었던 org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean 이녀석을 사용해서 FactoryBean을 사용했습니다.

사용자 삽입 이미지

사용자 삽입 이미지
흠냐.. 이제 정말 예제를 다 만들었습니다.  AOP 공부 하기 위한 예제를 만드는데 2시간이나 걸려네요. 후아~

'AOP' 카테고리의 다른 글

BeanNameAutoProxyCreator 사용 예  (0) 2007.04.01
Autoproxy  (0) 2007.04.01
Spring AOP(old) ProxyFactoryBean 불편한 점  (0) 2007.03.30
기선 씨네마 :: Pointcut  (0) 2007.03.30
기선 씨네마 :: Advice  (0) 2007.03.30
기선 씨네마 :: 티켓 만들어 주기  (0) 2007.03.30
Spring AOP 공부를 위한 예제 - 기선 씨네마  (0) 2007.03.30
Spring AOP(old) Pointcut Implementation  (0) 2007.03.28
Spring AOP(old) Advisor  (0) 2007.03.28
Spring AOP(old) Pointcut  (0) 2007.03.28
Spring AOP(old) Advice  (0) 2007.03.28
top


Spring AOP 공부를 위한 예제 - 기선 씨네마

AOP : 2007.03.30 11:58


사용자 삽입 이미지
AOP를 공부 할 영화관입니다.
사용자 삽입 이미지
영화관과 관련있는 도메인들 입니다. 고객이 중심이죠.

사용자 삽입 이미지
이렇게 설정 해놓고 다음과 같이 테스트를 해봤습니다.

사용자 삽입 이미지
별로 의미는 없는 테스트지만 일단 준비는 다 됐슴을 알리는 녹색 막대가 보고 싶어서요.ㅋ;

'AOP' 카테고리의 다른 글

Autoproxy  (0) 2007.04.01
Spring AOP(old) ProxyFactoryBean 불편한 점  (0) 2007.03.30
기선 씨네마 :: Pointcut  (0) 2007.03.30
기선 씨네마 :: Advice  (0) 2007.03.30
기선 씨네마 :: 티켓 만들어 주기  (0) 2007.03.30
Spring AOP 공부를 위한 예제 - 기선 씨네마  (0) 2007.03.30
Spring AOP(old) Pointcut Implementation  (0) 2007.03.28
Spring AOP(old) Advisor  (0) 2007.03.28
Spring AOP(old) Pointcut  (0) 2007.03.28
Spring AOP(old) Advice  (0) 2007.03.28
Spring AOP(old) 특징  (0) 2007.03.28
top


Spring AOP(old) Pointcut Implementation

AOP : 2007.03.28 11:24


이전에 살펴 봤듯이 포인트컷에는 두 가지 종류가 있습니다.

정적 포인트컷
- 직접 만들고 싶다면 StaticMethodMatcherPointcut 클래스를 상속하여 isMatch 메소드를 구현.
- NameMatchMethodPointcut :: NameMatchMethodPointcutAdvisor가 이에 상응하는 Advisor입니다. 클래스 이름에서 알 수 있듯이 메소드 이름으로 해당 포인트컷을 지정합니다.

사용자 삽입 이미지

위 두개의 setter를 사용하여 값을 configuration metadata 상에서 injection하면 됩니다. 위에껀 매칭되는 메소드 이름 설정이 하나일때 사용하고 아래는 여러개 일때 사용합니다.

매칭되는 메소드 이름 설정은 메소드 이름 앞이나 뒤에 *을 사용할 수 있습니다. 예) order* 은 oder로 시작하는 모든 메소드.

Sta*Meth* 이런식으로 *을 메소드 이름 중간에 넣으면 못 찾나? - 이건 나중에 코딩해보면서 확인해봐야겠습니다.

- Perl5RegexpMethodPointcut :: RegexpMethodPointcutAdvisor가 정규식을 사용한 포인트 컷을 받아 줄 수 있으며 JDK1.4 이상 부터는 기본으로 JdkRegexpMethodPointcut을 사용하는데 명시적으로 Perl5RegexpMethodPointcut을 사용할 수 도 있습니다.

NameMatchMethodPointcut과 다른 점은 무엇인가? - 정규 표현식을 사용한다는 것이고 메소드 이름으로만 포인트컷을 나타내는 것이 아니라 전체 패키지 경로와 클래스 이름까지 포함하여 나타내야 합니다.

Perl5RegexpMethodPointcut 과 JdkRegexpMethodPointcut 의 차이는 뭔가? - 둘 다 AbstractRegexpMethodPointcut 클래스를 상속한 자식 클래스들이며 정규 표현식으로 매칭되는 포인트컷을 정의할 때 사용합니다. Perl5RegexpMethodPointcut는 Perl5의 정규 표현식을 사용하며 Jakarta ORO regular expression library가 필요합니다. 측 추가적인 jar파일이 필요한거죠. 하지만 JdkRegexpMethodPointcut 는 JDK 1.4 정규표현식을 사용하며 추가적인 jar파일은 필요 없고 jdk버전이 1.4이상일 때 사용가능 합니다.

정규 표현식은 어떻게 쓰는거지? - SIA에 잘 나와있군요. 쩜(.), 별(*), 더하기(+), 역슬래쉬(\) 네가지를 사용합니다.
쩜(.)은 어떤 문자든 딱 한 글자를 나타냅니다.
별(*)은 * 전에 있는 문자가 0 ~ 여러개 있을 수 있슴을 나타냅니다.
더하기(+)는 + 전에 있는 문자가 1 ~ 여러개 있을 수 있슴을 나타냅니다.
역슬래쉬(\)는 \ 다음에 오는 문자가 있어야 한다는 것을 나타냅니다.
.*set.* :: set이라는 글자가 들어있는 모든 메소드
.*get.+By.+ :: get뭐시기By모시기 라는 형태의 글자가 들어있는 모든 메소드
거의 암호 수준이군요. 쩜별(.*) 은 쩜이 0~여러개 있을 수 있다는 거니까 그말은 다시 어떤 문자든지 여러개 있을 수 있다는 거니까 저렇게 되는거죠.

동적 포인트컷
- MethodMatcher를 구현하고 isRuntime() 메소드가 true를 리턴하게 합니다. 실행 중에 포인트컷에 해당하는 모든 메소드를 만날때 마다 matches(Method, Class, Object[]) 가 호출되기 때문에 상당한 성능 저하[각주:1]가 발생합니다.

- ControlFlowPointcut :: 이 포인트컷을 위한 Advisor가 따로 존재하진 않고 이전에 찾아냈던 DefaultPointcutAdivisor로 Pointcut 빈과 Advice 빈을 묶어줍니다. AspectJ의 cflow 포인트 컷에 해당하는 일을 합니다. 현재 동작중인 쓰레드 스택에서 특정한 클래스나 메소드가 찾아 졌을 경우에만 true를 리턴하도록 설정이 가능합니다.
사용자 삽입 이미지
이 생성자들을 사용하여 constuctor injection으로 쓰레드의 스택에서 어떤 타입의 어떤 메소드 이름의 메소드가 호출될 지점을 포인트컷으로 지정할 수 있습니다.
  1. API를 보니 "Note that evaluating such pointcuts is 10-15 times slower than evaluating normal pointcuts, but they are useful in some cases." 이렇게 나와있네요. [본문으로]
top


Spring AOP(old) Advisor

AOP : 2007.03.28 09:53


앞에서 살펴본 Advice와 Pointcut을 묶어서 하나의 Advisor로 만들 수 있습니다. 그 Advisor 하나를 보면 어디(Pointcut)에 뭐가(Advice) 적용될지 한눈에 보이게 됩니다.

이렇게 만든 Advisor 빈을 프록시 객체를 만들기 위한 ProxyFactoryBean에서 interceptorNames속성에 적어 주고, 타켓 빈을 target 속성에 적어 주고, 타켓 빈이 구현한 인터페이스를 proxyInterfaces에 적어 주면 프록시 bean을 사용할 수 있게 됩니다.

인터페이스가 없을 땐 CGLib을 사용한다고 했는데 어떻게 쓰는거지? 어딘가 예제가 나오겠지? 일단 지금은 그냥 인터페이스를 사용해서 프록시 객체 만드는 방법만...

사용자 삽입 이미지
Pointcut과 Advice를 설정할 수 있는 가장 일반적인 Advisor 클래스는 무엇인가? - 찾아봐야겠네요.
AbstractBeanFactoryPointcutAdvisor, AbstractGenericPointcutAdvisor, AbstractPointcutAdvisor, AspectJExpressionPointcutAdvisor, AspectJPointcutAdvisor, DefaultBeanFactoryPointcutAdvisor, DefaultPointcutAdvisor, DynamicMethodMatcherPointcutAdvisor, NameMatchMethodPointcutAdvisor, PersistenceExceptionTranslationAdvisor, ReflectiveAspectJAdvisorFactory.SyntheticInstantiationAdvisor, RegexpMethodPointcutAdvisor, StaticMethodMatcherPointcutAdvisor, TransactionAttributeSourceAdvisor
PointcutAdvisor 인터페이스를 구현한 클래스들 입니다. 이중에서 DefaultPointcutAdvisor가 setAdvice()와 setPointcut()을 가지고 있으니까 이녀석을 사용해서 따로 존재하는 pointcut과 advice를 합치면 될 것 같습니다.

보통은 PointcutAdvisor의 이름들을 보시면 Pointcut 이름 마다 거기에 해당하는 Advisor가 존재하는 것 같습니다. 그 말은 포인트컷 따로 어드바이스 따로 만들어서 DefaultPointcutAdvisor로 합치지 말고 어드바이스는 따로 만들고 포인트 컷은 Advisor의 속성에 직접 주입하는 방식으로 만들때 사용하라는 것 같습니다. 포인트 컷을 재사용할 것이 아니라면 그게 편하겠네요. 아마도 어드바이스는 재사용하기가 유리하지만 포인트컷은 해당 어플리케이션에 종속되기 쉬우니까 재사용이 어렵기 때문이겠죠.


top


Spring AOP(old) Pointcut

AOP : 2007.03.28 08:42


참조 : Reference 7.2, Spring In Action

Concept 
advice가 어떤 타입이든 상관없이 같은 포인트컷에 여러 adivce를 적용할 수 있습니다.
public interface Pointcut {
    ClassFilter getClassFilter();
    MethodMatcher getMethodMatcher();
}

핵심이 되는 포인트컷 인터페이스로 클래스와 메소드로 포인트컷을 판단하게 되기 때문에 저렇게 나뉘어져 있습니다. 클래스 필터와 메소드 필터의 재사용성을 고려한거라고 볼 수 있습니다.
public interface ClassFilter {
    boolean matches(Class clazz);
}

인자로 받은 클래스 타입에 따라 true, false를 리턴하면 되겠죠. 이 것 보다는 훨씬 복잡하고 중요한 것이 메소드 필터 입니다.
public interface MethodMatcher {
    boolean matches(Method m, Class targetClass);
    boolean isRuntime();
    boolean matches(Method m, Class targetClass, Object[] args);
}

왜 클래스 필터가 있는데 클래스를 인자로 받을까요? - 모르겠네..흠...

위에서 부터 차례대로 프록시 객체를 생성할 때 호출이 되며 먼저 matches(Method, Class)를 호출해서 ture면 isRuntime()이 호출 되는 때 이 때 정적 포인트컷이면 false를 리턴하고 동적 포인트컷이면 true를 리턴합니다. isRuntime이 false면 세번째 메소드는 호출하지 않고 true면 매번 advice가 적용될 때 마다 호출 하여 확인하게 됩니다.
정적 포인트컷 : matches(Method, Class)로 딱 한번 실행 됩니다.
동적 포인트컷 : matches(Method, Class, Object[])는 매번 adivce가 적용 될 때 마다 실행 되서 체크하게 됩니다.

동적 포인트컷을 확인할 때 인자를 받는 이유는? - 메소드 이름과 클래스 이름이나 타입만 가지고는 확인하는데 필요한 정보가 부족한가. 왜 그걸론 부족하지? - 메소드와 클래스 정보로 부족하다면 정적 포인트컷은 왜 인자를 받아 오지 않는거지..

포인트컷 연산
- union :: 합집합
- intersaction :: 교집합
Pointcuts 클래스에 있는 메소드를 사용합니다. 하지만 2.0에 추가된 AspectJ의 표현식을 사용하면 더 간단하죠. || 나 && 이런 걸로 해결이 가능하니까요.
top


Spring AOP(old) Advice

AOP : 2007.03.28 01:44


참조 : SIA 3장

Spring이 제공하는 Advice 종류와 특징
1. arond advice :: MethodInterceptor :: 대상 메소드에 대한 호출을 가로챔
2. before advice :: BeforeAdvice :: 대상 메소드가 실행되기 전에 호출됨
3. after advice :: AfterReturningAdvice :: 대상 메소드가 리턴한 후에 호출됨
4. throws advice :: ThrowsAdvice :: 대상 메소드가 예외를 던질 때 호출됨

2.0 부터는 after finally 였나.. 대상 메소드가 끝났거나 예외가 발생했거나 종료하면 무조건 실행하는 Advice가 추가 됐습니다.

1. Before Advice 만들기
MethodBeforeAdvice 인터페이스를 구현합니다. 구현해야 할 메소드는 한 개 입니다.

void before(Method method,
            Object[] args,
            Object target)
            throws Throwable

    Callback before a given method is invoked.

    Parameters:
        method - method being invoked
        args - arguments to the method
        target - target of the method invocation. May be null.
    Throws:
        Throwable - if this object wishes to abort the call. Any exception thrown will be returned to the caller if it's allowed by the method signature. Otherwise the exception will be wrapped as a runtime exception.

첫번째 인자는 대상이 되는 메소드
두번째는 그 메소드에 전달하는 인자들
세번째는 대상 메소드를 가지고 있는 객체

2. After Advice 만들기
AfterReturningAdvice 인터페이스를 구현합니다.

void afterReturning(Object returnValue,
                    Method method,
                    Object[] args,
                    Object target)
                    throws Throwable

    Callback after a given method successfully returned.

    Parameters:
        returnValue - the value returned by the method, if any
        method - method being invoked
        args - arguments to the method
        target - target of the method invocation. May be null.
    Throws:
        Throwable - if this object wishes to abort the call. Any exception thrown will be returned to the caller if it's allowed by the method signature. Otherwise the exception will be wrapped as a runtime exception.

첫번째 인자에 대상 메소드의 리턴값이 추가 됐고 나머진 한칸씩 밀렸습니다.
메소드가 끝난 뒤 실행하는 Advice니까 가용한 정보가 하나 늘었습니다.

3. Throws Advice 만들기
ThrowsAdvice 인터페이스를 구현합니다.

void afterThrowing( ThrowableSubclass)
void afterThrowing(Method , args, target, ThrowableSubclass)

위에 있는 두 가지 적어도 한 가지는 구현해야 합니다.
궁금한건... 이 인터페이스는 마커 인터페이스인데.. 어떻게 둘 중 하나만 구현하거나 둘 다 구현해도 되게 만든건지 신기합니다.

4. Around Advice 만들기
MethodInterceptor 인터페이스를 구현합니다.

가장 자주 사용될 것 같은 Advice로 Spring의 인터페이스가 아닌 AOP alliance의 인터페이스 입니다. 따라서 다른 AOP alliance 진영에 속한 AOP 구현체에서도 이 것을 구현한 Advice를 재사용할 수 있겠습니다.

public java.lang.Object invoke(MethodInvocation invocation)
                        throws java.lang.Throwable

    Implement this method to perform extra treatments before and after the invocation. Polite implementations would certainly like to invoke Joinpoint.proceed().

    Parameters:
        invocation - the method invocation joinpoint
    Returns:
        the result of the call to Joinpoint.proceed(), might be intercepted by the interceptor.
    Throws:
        java.lang.Throwable - if the interceptors or the target-object throws an exception.

유일한 인자인 MethodInvocation에는 getMethod()가 있어서 Method 타입의 객체를 넘겨 받을 수 있습니다.

리턴 타입이 있는 이유? 이 Advice는 대상 메소드의 리턴값을 바꿀 수 있습니다. 대상 메소드의 수행 여부 또한 결정할 수 있는 매우 강력한 기능을 가진 Advice입니다.

대상 메소드 실행 여부는 어떻게 결정하는가? invocation.proceed(); 를 넣어 주면 실행이 되고 해당 메소드가 값을 리턴 한다면 리턴 값을 받을 수도 있겠죠.

5. Introduction Adice

공부해야 할 것
top


Spring AOP(old) 특징

AOP : 2007.03.28 00:28


참조 : SIA 3장

1. Advice를 Java로 작성할 수 있다.
   
    advice를 자바 파일로 구현하고 pointcut을 xml설정에서 정의하고 그 두개를 묶어서 advisor를 역시 또 xml설정에서 만들고 advice가 적용될 target 객체의 proxy역시 ProxyFactoryBean을 xml에 설정 해줘서 만들 수 있습니다.
   
    별도의 언어(AspectJ)를 사용하여 만들면 그 언어의 문법을 배워야 한다는 단점이 있지만 훨씬 다양한 기능을 사용할 수 있다는 장점이 있다.

    2.0에서는 AspectJ의 포인트컷 표현 방법을 모두 사용할 수 있도록 개선 되었습니다.

2. Spring이 관리하는 객체에 대한 Advice는 런타임 때에 이뤄진다.

    프록시 객체가 필요하기 전까지는 프록시 객체를 만들지 않습니다.

    타겟 객체가 어떤 인터페이스를 구현하고 있을 때는 JDK의 Proxy 클래스를 사용하여 프록시 객체를 만들고 그렇치 않은 경우 CGLIB을 사용하여 타겟 객체의 서브 클래스를 만듭니다.

    인터페이스를 통한 프록시 생성이 프록시 클래스 보다 선호된다. 루즐리 커플드니까. 프록시 클래스의 경우 container에 관리되는 bean이 아닌 객체들도 advice가 적용될 수 있지만 이건 예외상황으로 봐야 한다.

    final 메소드는 advice가 적용될 수 없다. 오버라이딩 사용하기 때문에...

3. Spring은 AOP alliance 인터페이스를 구현한다.

    여러 AOP 구현체들 간의 표준화에 동참하는 격이다. AOP alliance의 인터페이스를 구현하면 다른 AOP 구현체 에서도 여기서 만든 advice를 사용할 수 있다.

4. Spring은 메소드 Joinpoint만 제공한다.
   
    다른 AOP 구현체들이 필드 joinpoint를 제공하는데 Spring의 철학으로 그런 방법은 캡슐화를 위반하기 때문에 메소드 joinpoint만 제공합니다.

    못 하는게 아니라 안 한다는거..
   
top


3월달 마소 AOP 기사 정리

AOP : 2007.03.27 18:03


1. 선택이 아닌 필수 AOP : AOP를 사용해야 하는 이유, AOP 도입 전략이 나와있습니다.

2. AOP 툴의 대명사 AspectJ : 가장 오래됐고 진보한 AspectJ 역사와 이를 사용할 때 도움을 주는 AJDT에 대해 소개합니다.

3. Spirng과 AOP의 절묘한 조화 Spring 2.0 AOP : 예전 SpringAOP와 Spring 2.0 AOP에 대해 소개합니다. 안그래도 Reference 6, 7장을 볼 차롄데 매우 잘됐습니다. 이 글을 먼저 정리하고 공부해야겠습니다.

4. 개발자 곁으로 성큼 다가온 AOP 실무에 활용하기 : Spring AOP를 사용하여 로깅, 모니터링, 보안을 처리하는 예제가 있습니다. 이 글도 역시 매우 잘됐네요. 3번 글을 자세히 정리하고 4번 예제를 돌려 본 다음에 레퍼런스 정리에 들어가면 한결 가벼운 마음으로 할 수 있겠습니다.

5. 닷넷 진영의 새바람 닷넷 AOP : 이글도 있지만 3, 4번 공부 하기도 바쁘기 때문에..
top


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

AOP : 2007.02.15 17:46



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

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


top


AOP: Radical Research in Modularity

AOP : 2007.02.04 00:13



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

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


12. Advice parameters 1

AOP : 2007.01.17 18:49



Around Advice를 제외한 Advice 메소드에 첫번개 매개변수로 JoinPoint 타입을 선언할 수 있습니다. Aroud Advice는 JoinPoint의 하위 타입인 ProceedingJoinPoint를 주어야 합니다.

AspectJ API : http://www.eclipse.org/aspectj/doc/next/runtime-api/index.html
위 API를 참조 하시면 어떤 메소드들이 있는지 확인 하실 수 있습니다.

Around Advice는 기능이 다른 Advice들과는 차이가 있습니다.

  • 해당 Join Point를 실행 할지 안할지 정할 수 있습니다.
  • Join Point의 아규먼트로 들어가는 값을 임의로 변경할 수 있습니다.
  • Join Point의 리턴값도 임의로 변경할 수 있습니다.

이를 위해서 두 개의 메소드가 존재합니다.

사용자 삽입 이미지

proceed() 메소드는 Join Point를 실행하기 위한 메소드 입니다. proceed()의 리턴 타입은 실제 Join Point에서 리턴하는 값을 리턴 해 줍니다.

proceed(Object[]) 메소드는 Join Point를 실행할 때 Join Point로 들어갈 아규먼트를 대체 하고 싶을 때 원하는 값을 Object 배열 형태로 넣어 줄 수 있습니다.

public class Test {

       public static void main(String[] args) {

 

             BeanFactory bf = new ClassPathXmlApplicationContext(

                           "parameter/joinpoint/aopAppContext.xml");

             Human human1 = (Human) bf.getBean("keesun");

             Human human2= (Human) bf.getBean("youngkun");

 

             System.out.println(human1.getName());

             System.out.println(human2.getName());

 

             human1.setName("찬욱");

 

             System.out.println(human1.getName());

       }

}


위에서 keesun이라는 bean의 name은 "기선" youngkun이라는 bean의 name은 "영근"으로 setter injection을 사용해서 값을 넣어뒀습니다.

@Aspect

public class HumanAspect {

 

       @Pointcut("execution(* get*(..))")

       public void sayHi() {

       }

 

       //리턴 변경하기.

       @Around("sayHi()")

       public Object say(ProceedingJoinPoint joinPoint) throws Throwable {

             System.out.println("안녕하세요.");

             Object name = joinPoint.proceed();

             return name;

       }

 

       //매개 변수의 임의로 변경하기.

       @Around("execution(* set*(..))")

       public void validate(ProceedingJoinPoint pjp) throws Throwable {

             System.out.println("모두 안녕~");

             pjp.proceed(new Object[]{"영회"});

       }

}


그리고 위와 같은 Aspect를 적용하면 결과는 다음과 같습니다.

안녕하세요.
기선
안녕하세요.
영근
모두 안녕~
안녕하세요.
영회


위의 Aspect에서 위에 있던 sayHi Advice를 다음과 같이 수정하면 결과는 다음과 같습니다.

       //리턴 변경하기.

       @Around("sayHi()")

       public Object say(ProceedingJoinPoint joinPoint) throws Throwable {

             System.out.println("안녕하세요.");

             Object name = joinPoint.proceed();

             return ".. 큰일났다.";

       }

 

안녕하세요.
앗.. 큰일났다.
안녕하세요.
앗.. 큰일났다.
모두 안녕~
안녕하세요.
앗.. 큰일났다.

그리고 하지 말라고 하면 더 하고 싶어지는.. 그런 장난끼에 ProceedingJoinPoint말고 그냥 JoinPoint로 선언한 뒤 실행하면 다음과 같은 출력이 됩니다.
안녕하세요.
null
안녕하세요.
null
모두 안녕~
안녕하세요.
null
top


11. within 포인트컷 & this 포인트컷 사용하기

AOP : 2007.01.16 19:21


within(Type)은 Type 안에 클래스 타입을 넣어줍니다. 그러면 그 클래스에 있는 메소드가 실행되는 시점들(Join point)을 포인트컷으로 묶습니다.

이번 예제 소스는 아래 파일에 있습니다.

@Aspect

public class MannerAOP {

 

       @Pointcut("within(Keesun) || within(Youngkun)")

       public void sayGoodBye(){}

 

       @AfterReturning("sayGoodBye()")

       public void say(){

             System.out.println("안녕히 가세요.");

       }

}


여기서 @Pointcut(within(Keesun) || within(Youngkun))[각주:1] 은 Keesun 클래스와 Youngkun클래스의 메소드를 호출하는 모든 Join point를 나타내게 됩니다.

두 클래스 모두 Human이라는 클래스를 구현하였기 때문에 within(Human)으로 하고 싶지만 Human은 인터페이스 이기 때문에 객체를 만들수 없으며 따라서 Human 객체의 메소드를 호출할 수도 없고 그럴 일도 없기 때문에 적용이 되지 않습니다. 이럴 때는 this를 사용합니다. 다음과 같이 수정하시면 위의 코드와 동일 한 결과를 얻을 수 있습니다.

@Aspect

public class MannerAOP {

 

       @Pointcut("this(Human)")

       public void sayGoodBye(){}

 

       @AfterReturning("sayGoodBye()")

       public void say(){

             System.out.println("안녕히 가세요.");

       }

}


  1. Pointcut들에 ||, &&, ! 연산을 할 수 있으며 의미는 알고 계신 의미와 동일합니다. [본문으로]
top


10. execution 포인트컷 사용하기

AOP : 2007.01.16 18:44


8번9번에서 살표봤던 포인트컷들을 사용해 보겠습니다.

@AspectJ 를 이용한 초간단 AOP 예제를 살짝 변경하여 사용해 보겠습니다.
소스파일은 아래 압축 파일로 묶어 뒀습니다.

import org.aspectj.lang.annotation.Aspect;

import org.aspectj.lang.annotation.Before;

 

@Aspect

public class MannerAOP {

 

       @Before("execution(* set*(String))")

       public void confirmName(){

             System.out.println("이름을 세팅합니다.");

       }

 

       @Before("execution(* set*(java.util.GregorianCalendar))")

       public void confirmBirthday(){

             System.out.println("생일을 세팅합니다.");

       }

 

       @Before("execution(* set*(int))")

       public void confirmAge(){

             System.out.println("나이를 세팅합니다.");

       }

}


세개의 Advice모두 익명 포인트 컷(= In-place 포인트 컷)으로 표현하였습니다.

첫번째 Advice는 리턴타입은 아무거나 상관 없고 메소드의 이름이 set으로 시작하고 아규먼트가 하나이며 String타입인 메소드를 나타낸 것입니다. 그것에 해당하는 것이 현재 name밖에 없기 때문에 Advice에는 "이름을 세팅합니다."를 출력하도록 했습니다.

세번째 것도 첫번째 것과 동일하며 조금 다른건 두번째 것입니다. 두번째 것은 아규먼트의 타입을 패키지 경로까지 포함해서 적어줬습니다. 기본으로 import되지 않는 패키지의 클래스들은 패키지 경로까지 써주어야 합니다.
top