Whiteship's Note


Introduction 예제

Spring/Chapter 6 : 2007.04.04 12:43


먼저 추가 할 기능의 명세서인 인터페이스가 필요하고 그것을 구현한 클래스가 필요합니다.

public interface TicketTracked {
    void incrementTicketCount();
}

public class TicketTrackedImpl implements TicketTracked {
    static int count = 0;
    public void incrementTicketCount() {
        System.out.println("표 " + (++count) + " 장 팔았다.");
    }
}

그리고 어스팩트에 @DeclareParents를 사용하여 static 필드를 추가합니다.

    /** introduction **/
    @DeclareParents(value="aop.newStyle.domain.KeesunCinema", defaultImpl=TicketTrackedImpl.class)
    public static TicketTracked mixin;

    @After("sellTicketPointcut() &&" + "this(ticketTracked)")
    public void ticketTtrack(TicketTracked ticketTracked){
        ticketTracked.incrementTicketCount();
    }

@DeclareParents 의 value 속성에는 새 기능(TIckTracked 인터페이스 구현체)을 추가할 클래스를 지정해 줍니다. * 을 사용하여 여러 클래스를 지정할 수도 있습니다. deaultImplt 에는 새 기능을 가진 클래스를 지정해 줍니다.

테스트를 해봅니다.
    @Test
    public void pointcutWithin(){
        cinema.sellTicket(movie, new Date());
        cinema.sellTicket(movie, new Date());
        cinema.sellTicket(movie, new Date());

        TicketTracked cinemaTicketTracked = (TicketTracked)cinema;
    }

표 세장을 사고 cinema가 제대로 TicketTracked 인터페이스를 추가로 구현했는지 확인해봤습니다. 테스트는 무난히 통과 하고 결과는 다음과 같습니다.
표 1 장 팔았다.
표 2 장 팔았다.
표 3 장 팔았다.



top

Write a comment.


Advice ordering

Spring/Chapter 6 : 2007.04.04 11:59


@Aspect
public class CinemaAspect {

    @Pointcut("execution(aop.newStyle.domain.Ticket *.sell*(..))")
    public void sellTicketPointcut() {
    }

    @Before("sellTicketPointcut()")
    public void before1(){
        System.out.println("표 팔기 전 1");
    }

    @Before("sellTicketPointcut()")
    public void before2(){
        System.out.println("표 팔기 전 2");
    }

    @After("sellTicketPointcut()")
    public void after1(){
        System.out.println("표 팔고 나서 1");
    }

    @After("sellTicketPointcut()")
    public void after2(){
        System.out.println("표 팔고 나서 2");
    }
}

@Aspect
public class AnotherCinamaAspect {

    @Before("aop.newStyle.aspect.CinemaAspect.sellTicketPointcut()")
    public void before3(){
        System.out.println("표 사기 전 3");
    }

    @After("aop.newStyle.aspect.CinemaAspect.sellTicketPointcut()")
    public void after3(){
        System.out.println("표 사고 나서 3");
    }
}

다른 어스팩트 하나를 추가했습니다. 포인트컷은 이전 어스팩트와 같은 곳으로 지정했습니다. 결과는 다음과 같습니다.

이 두개의 어스팩트를 다음과 같은 순서로 등록해 두었습니다.
<bean id="anotherCinemaAspect" class="aop.newStyle.aspect.AnotherCinamaAspect" />
<bean id="cinemaAspect" class="aop.newStyle.aspect.CinemaAspect" />

결과는 다음과 같습니다.
표 팔기 전 3
표 팔기 전 1
표 팔기 전 2
표 팔고 나서 1
표 팔고 나서 2
표 팔고 나서 3

두 어스팩트를 등록한 순서를 바꿨더니 결과가 아래 처럼 바꼈습니다.
표 팔기 전 1
표 팔기 전 2
표 팔기 전 3
표 팔고 나서 3
표 팔고 나서 1
표 팔고 나서 2
before는 먼저 등록 bean에 있는 걸 먼저 실행하고 after는 나중에 등록된 bean에 있는 걸 먼저 실행합니다. 같은 bean 안에서는 before든 after든 등록 된 순서대로 실행됩니다.
두 개의 어스팩트 적용 순서를 Ordered 인터페이스나 @Order 어노테이션을 사용해서 getValue에서 낮은 값을 리턴할 수록 높은 우선 순위를 갖게 할 수 있다고 하는데 흠.. 테스트를 해봤는데 잘 안되는군요.

그렇게 하지 않아도 어차피 설정 파일에서 bean의 등록 순서가 위에 있을 수록 우선 순위가 높다는 걸 유념하면 되겠습니다.
top

Write a comment.


Advice parameters

Spring/Chapter 6 : 2007.04.03 15:33


예전에 공부할 때 여기를 공부하다가 멈췄었네요.
Advice parameters 1 (2)
드디어 따라잡았습니다. 흐흣.

1. Access to the current JoinPoint

해당 Advice가 끼어드는 joinpoint에 대한 정보를 얻어 올 수 있습니다. @Around 어드바이스를 제외한 다른 어드바이스들의 첫번째 파라미터로 JoinPoint 를 만들어 주면 됩니다.

    @Before("aop.newStyle.aspect.CinemaAspect.sellTicketPointcut()")
    public void weblcomeAdvice(JoinPoint jp){
        System.out.println(jp.getClass());
        System.out.println("안녕하세요. 어떤 영화를 보시겠습니까?");
    }

실제 객체는 MethodInvocationProceedingJoinPoint 이 클래스라는 걸 확인할 수 있습니다.

@Around 어드바이는 이전 글에서 봤듯이 ProceedingJoinPoint가 와야 합니다.

2. Passing parameters to advice

    @Pointcut("execution(aop.newStyle.domain.Ticket *.sell*(..))")
    public void sellTicketPointcut() {
    }

    @Before("aop.newStyle.aspect.CinemaAspect.sellTicketPointcut() &&" +
            "args(movie, ..)")
    public void weblcomeAdvice(JoinPoint jp, Movie movie){
        System.out.println("안녕하세요." + movie.getName() + " 을(를) 보시겠습니까?");

이렇게 args()를 사용하여 대상 메소드가 받을 인자를 가져올 수 있습니다.

다른 방법으로는 @Pointcut을 정의할 때 args()를 사용해서 다음과 같이 하는 건데요. IllegalArgumentExecption이 발생하는데 아직 원인을 모르겠습니다. 레퍼런스에 나와있는 코드와 똑같이 친것 같은데 말이죠. ㅠ.ㅠ

3. Determining argument names

공부해야 할 부분

4. Proceeding with arguments

@Around 에서 proceed()를 실행 할 때 들어갈 인자값을 바꿀 수 있는데요 그때는 proceed(Object[]) 메소드를 사용하면 됩니다.

@Around("aop.newStyle.aspect.CinemaAspect.sellTicketPointcut() && " +
            "args(movie,..)")
    public Object ticketAround(ProceedingJoinPoint pjp, Movie movie) throws Throwable{
        System.out.println("안녕하세요." + movie.getName() + " (을)를 보시겠습니까?");
        Ticket ticket = (Ticket)pjp.proceed(new Object[]{movie, new Date()});
        System.out.println(ticket.getMovie().getName() + " 를 구매하셨습니다.");
        System.out.println("감사합니다. 다음에 또 오세요.");
        ticket.getMovie().setName("바뀐 영화 이름");
        return ticket;
    }

top

Write a comment.


6.2. @AspectJ support

Spring/Chapter 6 : 2007.04.03 14:10


@AspectJ 는 Java 5에 추가된 어노테이션을 사용하여 aspect를 정의하는 스타일을 말하며 이것은 AspectJ 라이브러리를 사용하여 AspectJ 5와 동일한 방법으로 aspect와 pointcut을 정의할 수 있습니다.

하지만 Spring AOP를 사용하여 실행하기 때문에 AspectJ의 weaver나 complier는 사용하지 않아도 됩니다. 그것들을 사용하면 AspectJ의 모든 기능을 사용할 수 있습니다.

6.2.1. Enabling @AspectJ Support

autoproxing을 사용하여 자동으로 aspect가 적용될 bean의 프록시를 만들게 됩니다. 이렇게 하려면 설정파일에 간단한 설정을 추가해 주면 됩니다.

스키마 기반의 XML에서는 다음의 한 줄을 추가하면 됩니다.
<aop:aspectj-autoproxy/>

DTD 기반의 XML에서는 다음과 같이 적어 줍니다.
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />

아마도 내용은 동일한데 스키마 기반이라 네임스페이스를 달리하여 좀 더 간단하게 선언할 수 있는듯 합니다.

XML 스키마(Schema) (2)

6.2.2. Declaring an aspect

@Aspect를 클래스 선언 위에 붙여 줍니다. 그리고 bean으로 등록하여 주기만 하면BeanPostProcessor가 알아서 찾아서 Spring AOP 설정으로 사용하게 될 겁니다.

물론 일반 클래스기 때문에 평범한 클래스처럼 사용할 수 있습니다. 아마도 그렇기 때문에 투명성(transparency)을 보장하게 됐다는 것이 아닌가 싶습니다. 자기 자신이 Aspect로 사용되지만 일반 클래스와 다를바가 없기 때문이죠.(물론 어노테이션이 좀 붙는 건 어쩔 수 없겠지만요.ㅋㅋ)

Enabling @AspectJ Support

6.2.3. Declaring a pointcut

pointcut 선언은 두 부분으로 나눠집니다. pointcut 서명(signature) 부분과 표현(expression) 부분입니다.
서명 부분은 일반 메소드 선언 부분과 동일합니다.(반드시 리턴타입이 void 여야 합니다.)
표현 부분은 @Pointcut 을 사용하며 AspectJ 5의 형식을 사용합니다.

초간단 @Pointcut 과 @Advice 예제
@Pointcut Designator

6.2.4. Declaring advice

pointcut 표현식과 함께 사용할 수 도 있고 pointcut 이름을 사용하여 특정 메소드의 실행 전, 후, 예외가 발생했을 때 등에 할일을 추가할 수 있습니다.

@Before("com.xyz.myapp.SystemArchitecture.dataAccessOperation()")
이런식으로 @Before 를 사용하여 before advice를 만들 때 이 advice가 적용될 포인트 컷의 이름을 줄 수 있으며

@Before("execution(* com.xyz.myapp.dao.*.*(..))")
이렇게 직접 pointcut 표현식을 사용하여 advice가 적용될 지점을 나타낼 수도 있습니다.(in-place pointcut)

같은 pointcut이 여러 advice에서 사용될 거라면 이름을 사용하는 방법이 좋겠죠.

@AfterReturning 어드바이스 만들기
@Around 어드바이스 예제
Advice parameters
Advice ordering

6.2.5. Introductions

@DeclareParents 을 사용하여 선언하며 지정된 타입들이 새로운 부모 클래스를 상속 받도록 합니다.

새로 추가 할 메소드나 필드를 모아놓은 인터페이스를 만들고 그 인터페이스를 구현한 클래스를 만듭니다. 그리고 이 인터페이스의 기능을 추가할 대상 클래스들을 지정해 주고 구현한 클래스를 묶어 주면 대상 클래스들도 해당 인터페이스 타입으로 사용할 수 있게 됩니다. 즉 새로운 메소드와 필드를 추가적으로 사용할 수 있게 됩니다.

Introduction 예제

6.2.6. Aspect instantiation models

@Aspect의 속성으로 perthis와 pertarget을 사용할 수 있습니다.

perthis는 해당 포인트컷에 매칭되는 메소드를 실행할 때 새로운 Aspect 객체를 만들고 그 메
소드를 가진 객체와 연관을 맺게 됩니다. 즉 타겟 객체와 묶이게 되는거죠. 해당 타겟 객체와 연관된 aspect 객체가 만들어 지기 전가진 advice가 적용되지 않습니다.

pertarget는 perthis와 다른건 포인트컷에 매칭되는 메소드를 가진 객체들 마다 새로운 aspect객체를 만들지 않고 딱 하나만 만든다는 것만 다르고 나머진 같습니다.

6.2.7. Example

around advice를 사용하여 PessimisticLockingFailureException을 잡아서 처리하고 사용자에게 안 보이도록 하는 aspect를 만들어 봅니다.

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

Schema 기반 Spring AOP 희한한 것  (0) 2007.04.05
초간단 Schema 기반 Spring AOP  (0) 2007.04.05
Introduction 예제  (0) 2007.04.04
Advice ordering  (0) 2007.04.04
Advice parameters  (0) 2007.04.03
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
top

Write a comment.


@Around 어드바이스 예제

Spring/Chapter 6 : 2007.04.03 14:07


이전까지 사용했던 @Before와 @AfterReturning 대신 @Around 어드바이스 하나로 기존에 했던 인사말들을 모두 처리할 수 있습니다.

더불어 리턴값도 변경할 수 있으며 대상 메소드의 실행 여부도 결정할 수 있습니다. 제약조건은 어드바이스의 메소드 첫번째 인자로 ProceedingJoinPoint 가 와야 하며 실제로는 이 인터페이스를 구현한 MethodInvocationProceedingJoinPoint 이녀석의 객체가 넘어옵니다.
    @Around("aop.newStyle.aspect.CinemaAspect.sellTicketPointcut()")
    public Object ticketAround(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("안녕하세요. 어떤 영화를 보시겠습니까?");
        Ticket ticket = (Ticket)pjp.proceed();
        System.out.println(ticket.getMovie().getName() + " 를 구매하셨습니다.");
        System.out.println("감사합니다. 다음에 또 오세요.");
        return ticket;
    }

이렇게 만들면 이전에 만들었던 @Before와 @AfterReturning을 대체할 수 있는 어드바이스를 만들 수 있습니다.

신기한게 있는데요. 대상이 되는 메소드를 실행하고 그 결과 리턴되는 값을 바로 넘겨 주었더니 원래 넘겨줬던 티켓 객체와 같은 객체가 맞습니다.
    @Test
    public void sellTicket() {
        hein.buyTicket(cinema, movie);
        Ticket ticket = hein.getTicket();
        Movie movie2 = ticket.getMovie();
        assertEquals(movie2, movie);
    }

하지만 중간에 객체의 속성을 바꾼다던가 하면...다른 객체가 됩니다. 즉 @Around 에서 리턴값의 속성을 다음 처럼 바꾸는 일을 합니다.

    @Around("aop.newStyle.aspect.CinemaAspect.sellTicketPointcut()")
    public Object ticketAround(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("안녕하세요. 어떤 영화를 보시겠습니까?");
        Ticket ticket = (Ticket)pjp.proceed();
        System.out.println(ticket.getMovie().getName() + " 를 구매하셨습니다.");
        System.out.println("감사합니다. 다음에 또 오세요.");
        ticket.getMovie().setName("바뀐 영화 이름");
        return ticket;
    }

그리고 다음과 같은 테스트를 통해서 리턴값이 원래 객체와 다른 객체가 되고 값도 바뀐 것을 확인할 수 있습니다.
    @Test
    public void sellTicket() {
        hein.buyTicket(cinema, movie);
        Ticket ticket = hein.getTicket();
        Movie movie2 = ticket.getMovie();
        assertNotSame(movie2, movie);
        assertEquals("바뀐 영화 이름", movie2.getName());
    }


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

초간단 Schema 기반 Spring AOP  (0) 2007.04.05
Introduction 예제  (0) 2007.04.04
Advice ordering  (0) 2007.04.04
Advice parameters  (0) 2007.04.03
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
top

Write a comment.


@AfterReturning 어드바이스 만들기

Spring/Chapter 6 : 2007.04.03 12:15


제일 간단한 @AfterrReturning 어드바이스는 다음과 같습니다.
    @AfterReturning("aop.newStyle.aspect.CinemaAspect.sellTicketPointcut()")
    public void thanksAdvice(){
        System.out.println("감사합니다. 다음에 또 오세요.");
    }

@AfterReturning 어드바이스는 대상 메소드의 리턴값을 받아 올 수 있습니다. @AfterReturning의 속성인 returning을 사용하면 됩니다. 다음과 같이 작성할 수 있습니다.
    @AfterReturning(pointcut="aop.newStyle.aspect.CinemaAspect.sellTicketPointcut()", returning="ticket")
    public void thanksAdvice(Ticket ticket){
        System.out.println(ticket.getMovie().getName() + " 를 구매하셨습니다.");
        System.out.println("감사합니다. 다음에 또 오세요.");
    }

이렇게 하면 될 것 같지만...에러가 나지요. asm 라이브러리를 추가해줘야 합니다.
사용자 삽입 이미지

저 두개의 라이브러리를 프로젝트에 추가하면 돌아갑니다~
안녕하세요. 어떤 영화를 보시겠습니까?
공공의적 를 구매하셨습니다.
감사합니다. 다음에 또 오세요.

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

Introduction 예제  (0) 2007.04.04
Advice ordering  (0) 2007.04.04
Advice parameters  (0) 2007.04.03
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
top

Write a comment.


@Pointcut Designator

Spring/Chapter 6 : 2007.04.02 19:02


@AspectJ의 Pointcut 살펴보기 1
@AspectJ의 Pointcut 살펴보기 2

이전 글에서 정리를 했지만 좀 더 간단하게 정리 하겠습니다. pointcut 종류에 따라 표현식이 조금씩 다르지만 크게 세분류로 나눌 수 있습니다.
  • execution(method signature), call(method signature)
  • target(type signature), this(type signature), agrs(type signature)
  • @target(annotation name), @args(annotation name), @within(annotation name), @annotation(annotation name)
1. method signature는 다음과 같습니다.
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern)
         throws-pattern?)

접근지시자 패턴(modifiers-pattern)은 생략 가능합니다.
retyrn type 패턴은 * 을 사용하여 모든 리턴타입을 나타낼 수 있습니다.
타입 패턴(declaring-type-pattern)역시 생략 가능합니다.
메소드 이름 패턴(name-pattern)은 타입패턴과 붙여서 사용 합니다.

execution( aop.newStyle.domain.Ticket *.sell*(..))
=> 어떤 접근지시자든 상관없고 Ticket을 리턴하는 sell로 시작하는 메소드

execution(public aop.newStyle.domain.Ticket *.sell*(..))
=> public 접근지시자를 가지고 있고 Ticket을 리턴하고 sell로 시작하는 메소드

그럼 default 접근지시자는 어떻게 표현하지? - 접근지시자를 생략하면 모든 접근지시자로 인식하고 써주면 해당 접근지자면.. default라고 써주면 에러가 납니다. 흠.. 어떻게 하지..;;

execution(* set*(..))
=> 접근지시자와 리턴타입은 상관없고 set으로 시작하는 모든 메소드

2. type signature는 method signature에서dml type pattern과 같습니다.
AspectJ에서 this와 target은 같은 객체를 나타내지만 Spring AOP에서는 프록시를 사용하고 있기 때문에 this는 프록시 객체를 나타내고 target은 프록시 객체가 감싸는 객체를 나타냅니다. 즉 다른 객체 입니다.

3. annotaion name은 제일 상단 링크 중 두번째 것을 참조하시면 알 수 있습니다.

현재까지는 위에 적혀있는 designator들만 지원이 되며 차후에 AspectJ에 있는 다른 designator들(call, initialization, preinitialization, staticinitialization, get, set, handler, adviceexecution, withincode, cflow, cflowbelow, if, @this, @withincode)도 추가될 예정입니다.

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

Advice ordering  (0) 2007.04.04
Advice parameters  (0) 2007.04.03
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
top

Write a comment.


@Aspect 붙은 클래스끼리는 상속이 안 됩니다.

Spring/Chapter 6 : 2007.04.02 15:53


이전 글을 작성하다가 문든 들은 생각(@Aspect 가 붙은 클래스들끼리 상속을 하면 포인트컷과 어드바이스를 상속할 수 있는가?)을 실험해봤습니다.
//CinamaAspect
@Aspect
public class CinemaAspect {

    @Pointcut("execution(* sellTicket(..))")
    public void sellTicketPointcut() {
    }

    @Before("aop.newStyle.aspect.ChildAspect.sellTicketPointcut()")
    public void weblcomeAdvice(){
        System.out.println("안녕하세요. 어떤 영화를 보시겠습니까?");
    }
}

//ChildAspect
@Aspect
public class ChildAspect extends CinemaAspect {

}

그리고 이전에 테스트를 돌리면 다음과 같은 에러메시지를 볼 수 있습니다.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name '혜인' defined in class path resource [aop/newStyle/watchingMovieConfiguration.xml]: Cannot resolve reference to bean 'KCcard' while setting bean property 'card'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'KCcard' defined in class path resource [aop/newStyle/watchingMovieConfiguration.xml]: Initialization of bean failed; nested exception is org.springframework.aop.framework.AopConfigException: aop.newStyle.aspect.ChildAspect cannot extend concrete aspect aop.newStyle.aspect.CinemaAspect
...

concrete aspect를 상속할 수 없다고 하길래 인터페이스를 만들어서 실험해 봤습니다.
//AbstractAspect
@Aspect
public interface AbstractAspect {
    @Pointcut("execution(* sellTicket(..))")
    public void sellTicketPointcut();
}

//ChildAspect
@Aspect
public class ChildAspect implements AbstractAspect {

    /* (non-Javadoc)
     * @see aop.newStyle.aspect.AbstractAspect#sellTicketPointcut()
     */
    public void sellTicketPointcut() {
    }
}

//설정파일
    <bean id="cinemaAspect" class="aop.newStyle.aspect.CinemaAspect" />
    <bean id="childAspect" class="aop.newStyle.aspect.ChildAspect" />
    <bean id="abstractAspect" class="aop.newStyle.aspect.AbstractAspect" abstract="true"/>

하지만 역시 에러가 납니다.
org.springframework.beans.factory.BeanCreationException: Error creating bean with name '혜인' defined in class path resource [aop/newStyle/watchingMovieConfiguration.xml]: Cannot resolve reference to bean 'KCcard' while setting bean property 'card'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'KCcard' defined in class path resource [aop/newStyle/watchingMovieConfiguration.xml]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 can't make static reference to abstract pointcut
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'KCcard' defined in class path resource [aop/newStyle/watchingMovieConfiguration.xml]: Initialization of bean failed; nested exception is java.lang.IllegalArgumentException: error at ::0 can't make static reference to abstract pointcut
Caused by: java.lang.IllegalArgumentException: error at ::0 can't make static reference to abstract pointcut...

흠.. ChildAspect에 있는 @Aspect 를 제거하고 다시 상속을 사용해봤습니다.
//CinemaAspect
@Aspect
public class CinemaAspect {

    @Pointcut("execution(* sellTicket(..))")
    public void sellTicketPointcut() {
    }

    @Before("aop.newStyle.aspect.ChildAspect.sellTicketPointcut()")
    public void weblcomeAdvice(){
        System.out.println("안녕하세요. 어떤 영화를 보시겠습니까?");
    }
}

//ChildAspect
public class ChildAspect extends CinemaAspect {

}

이렇게 하니까 제대로 동작을 합니다. 포인트컷은 상속이 되는 걸 확인했습니다. 하지만..advice를 ChileAspect로 옮겨 놓으니까 제대로 동작하지 않네요. 당연히...안되죠. ChileAspect는 이름만 Aspect일뿐 일반 클래스기 때문에 @Advice가 붙어 있다 하더라도 인식하지 않습니다.


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

Advice parameters  (0) 2007.04.03
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
top

Write a comment.


초간단 @Pointcut 과 @Advice 예제

Spring/Chapter 6 : 2007.04.02 15:28


@Aspect
public class CinemaAspect {

    @Pointcut("execution(* sellTicket(..))")
    public void sellTicketPointcut() {
    }

    @Before("aop.newStyle.aspect.CinemaAspect.sellTicketPointcut()")
    public void weblcomeAdvice(){
        System.out.println("안녕하세요. 어떤 영화를 보시겠습니까?");
    }
}

설정파일에 이 Aspect를 bean으로 등록합니다. pointcut의 이름에 해당하는 public void sellTicketPointcut() 부분에서 리턴타입은 항상 void여야 합니다. 접근지시자는 다른 Aspect에서 해당 포인트컷을 참조 할 수 있는 범위를 나타내게 됩니다. 일반적인 메소드 접근지시자와 동일하게 사용됩니다.

@Aspect 가 붙은 클래스들 끼리 상속을 하게 되면 어떻게 되나? - 포인트 컷과 어드바이스도 상속이 되는건가? 일단 지금은 초간단 이니까 바로 다음 글에 이어서 실험하도록 하겠습니다. [각주:1]

    <!-- @Aspect 시작 -->
    <aop:aspectj-autoproxy/>

    <bean id="myAspect" class="aop.newStyle.aspect.CinemaAspect" />

테스트 코드에서 sellTicket을 호출하게 되는 buyTicket을 호출 합니다.

    @Test
    public void sellTicket() {
        hein.buyTicket(cinema, movie);
    }

안녕하세요. 어떤 영화를 보시겠습니까?

원하는 결과를 확인할 수 있습니다.

  1. 이건 마치 무슨 '호기심 천국'이나 '스펀지 연구소'가 된 분위기가 납니다. 물론 쏠로로 진행하지만 말이죠.ㅋㅋ [본문으로]

'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.


Enabling @AspectJ Support

Spring/Chapter 6 : 2007.04.02 14:50


@AsprctJ 사용을 위한 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">

    <!-- @Aspect 시작 -->
    <aop:aspectj-autoproxy/>

</beans>

찐한 색에 해당하는 부분이 기본적인 XML 설정에 추가 되는 부분입니다.

그리고 두개의 jar파일을 추가해 주면 준비가 끝납니다.
사용자 삽입 이미지

'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.


6.1. Introduction

Spring/Chapter 6 : 2007.04.01 00:11


선언적 트랜잭선 관리(declarative transaction management)와 같이 EJB를 대체할 만한 선언적인 엔터프라이즈 서비스를 제공하기 위해 사용하며, 이것으로 OOP를 보완 하기 위해 사용자 정의 apect를 만들어 사용할 때 유용합니다.

6.1.1. AOP concepts

Aspect : 여러 객체를 관통하는 cross-concern을 구현한 것.
Join Point : 프로그램이 실행되는 동안의 여러 시점들.. 그 중에서 Spirng AOP는 메소드 실행 시점 만을 나타냅니다.
Advice : Aspect에 의해 제공되어 특정 join point에 끼어들어 수행하게 될 작업.
Pointcut : 특정 Join point들을 나타내는 표현 방법.
Introduction : 프록시 객체에 추가적인 메소드나 필드를 추가하는 것.
Target object : 하나 또는 여러개의 aspect에 의해 advice가 적용될 객체.
AOP proxy : Aspect를 구현하기 위해 Spring 프레임웤에서 만들어 내는 객체로, JDK의 Proxy인터페이스 또는 CGLib을 사용합니다. Spring 2.0을 사용하면 투명성을 유지하면서[각주:1] 프록시를 만들 수 있습니다.
Weaving : Aspect를 target 객체에 적용하는 걸 말하며, 컴파일, 클래스 로드, 런타임 때 할 수 있으나 Spring AOP는 런타임 때 합니다.

Advice Type
Before advice : 해당 join point 전에 실행 할 adive.
After returning advice : 해당 join point가 정상적으로 종료 된 뒤에 실행 할 advice
After throwing advice : 해당 join point에서 예외가 발생했을 때 실행 할 advice
After (finally) advice :  해당 join point가 정상적으로 끝나든 예외가 발생하든 무조건 실행 할 advice
Around advice :  위에서 언급한 모든 adivce의 일을 할 수 있고 해당 join point의 실행 여부도 결정할 수 있으며 join point가 반환할 값을 조작할 수 도 있습니다.

Using the most specific advice type provides a simpler programming model with less potential for errors.

6.1.2. Spring AOP capabilities and goals

Spring AOP는 자바로 구현했기 때문에 별도의 컴파일 처리가 필요로 하지 않습니다.

Spring AOP는 위에서도 잠시 언급했지만 메소드 실행 join point만 제공합니다.

완벽한 AOP구현이 목적이 아니라 다른 AOP 구현체와의 통합이 목표입니다. 하지만 대부분의경우 Spring AOP만으로도 충분합니다.

AspectJ와 경쟁을 하려는 것이 아니고 프록시 기반의 Spring AOP와 완전한 AOP 프레임워크인 AspectJ는 서로 상호 보완의 관계입니다.

6.1.3. AOP Proxies


6.6 에서 더 자세히 살펴 보겠지만 기본적으로 J2SE의 dynamic proxy[각주:2]를 사용합니다.

그밖에 CGLIB proxy를 사용하게 될 경우는 다음과 같습니다.
인터페이스를 구현하지 않은 클래스의 프록시를 만들 때
인터페이스에 없는 메소드를 가진 클래스의 프록시를 만들고 싶을 때
메소드의 인자로 인터페이스 타입이 아닌 특정 클래스 타입의 프록시를 넘겨주고 싶을 때
  1. 이전에는 일일히 ProxyFactoryBean을 사용하여 만들어 줬었는데 이제는 그런 일을 안해도 된다는 의미 인듯 합니다. [본문으로]
  2. 인터페이스를 사용하여 프록시를 만듭니다. [본문으로]

'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.


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

Write a comment.


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

Write a comment.


9. @AspectJ의 Pointcut 살펴보기 2

AOP : 2007.01.16 17:36


참조 : http://www.eclipse.org/aspectj/doc/released/progguide/semantics-pointcuts.html

this(Type)
  • this 키워드에 바인딩 되는 현재 실행 중인 객체의 타입이 Type인 경우에 모든 메소드 execution Join point를 나타냅니다.
target(Type)
  • 메소드가 호출되거나 필드가 접근 되는 객체의 타입이 Type인 경우에 그 객체의 모든 메소드 execution Join point를 나타냅니다.
args( Type or ".." or * )
  • 메소드의 아규먼트가 () 안에 정의한 갯수나 타입에 매칭 되는 모든 메소드 exexution Join point를 나타냅니다.
@targer(Type)
  • 타켓 객체(메소드가 호출되거나 필드가 접근 되는 객체)에 @Type 어노테이션이 붙어있을 때 그 객체의 모든 메소드 execution Join point를 나타냅니다.
@within(Type)
  • 선언된 타입에 @Type 어노테이션이 붙어있을 때 그 객체의 모든 execution Join point를 나타냅니다.
@annotation(Type)
  • 실행되는 메소드에 @Type 어노테이션이 붙어있을 때 그 메소드의 execution Join point를 나타냅니다.
@args(Type)
  • 실행시 아규먼트로 넘겨지는 것에 @Type 어노테이션이 붙어있을 때 그 메소드의 execution Join point를 나타냅니다.
top

Write a comment.


8. @AspectJ의 Pointcut 살펴보기 1

AOP : 2007.01.16 12:47


참조 : Spring Reference 6.2.3.4

execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
  • 빨간색으로 표시된 return type pattern을 제외 하고는 전부 optional입니다.
  • modifiers-pattern은 advice가 적용될 메소드의 접근 지시자 형태를 정합니다. * 은 모든 메소드 public은 public 메소드만... 뭐 그런 식입니다.
  • declaring-type-pattern은 인터페이스나 패키지 패턴을 나타내는 부분인듯 합니다.
  • name-pattern은 메소드의 이름의 형태를 지정해 줍니다. set* 과 같이 하면 set으로 시작하는 모든 메소드를 나타냅니다.
  • param-pattern은 조금 특이합니다. ()은 파라미터가 없는 메소드를 가리키고, (..)는 파라미터가 어떤 형태든 몇 개든 상관없슴을 나타냅니다. 다른 패턴들이 * 와일드 카드를 사용하는 것과는 차이가 있네요. (*, String) 이것은 파라미터가 두 개고 첫번 째 파라미터의 타입은 상관이 없고 두 번째 파라미터의 타입이 String인 메소드를 나타냅니다.
within(type-pattern)
  • within은 Spring AOP가 메소드 execution 포인트컷만 지원하기 때문에 해당 타입과 관련된 모든 메소드 실행시점을 가리키게 됩니다. AspectJ를 사용할 때는 훨씬 다양한 포인트컷[각주:1]을 나타내게 됩니다.
  • within(com.xyz.service.*) 이것 같은 경우는 com.xyz.service 패키지 안에 있는 모든 클래스의 모든 메소드의 실행 시점을 나타냅니다.
  1. 클래스 초기화 시점, 객체 초기화 시점, 생성자 실행 시점, 메소드 실행 시점 이밖에도 변수들에 대한 포인트컷까지 적용되며 내부 클래스가 있을 경우 그 것의 생성자나 기타 내부 클래스와 관련된 모든 join point에도 적용 됩니다. [본문으로]
top

Write a comment.


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

AOP : 2007.01.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.