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

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 장 팔았다.