이전까지 사용했던 @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());
    }