Whiteship's Note


6.4. Choosing which AOP declaration style to use

Spring/Chapter 6 : 2007.04.06 13:02


6.4.1. Spring AOP or full AspectJ?

Spring AOP는 별도의 컴파일러나 위버가 필요 없으며 AspectJ 보다 단순합니다. 하지만 컨테이너에 의해 관리되는 bean에만 advice를 적용할 수 있고 적용되는 joinpoint가 메소드 실행 시점 뿐 입니다.

도메인 객체 또는 컨테이너에 의해 관리되지 않는 객체들에 Advice를 적용해야 하거나 더 다양한 joinpoint가 필요하다면 AspectJ를 사용하는 것이 좋겠습니다.

6.4.2. @AspectJ or XML for Spring AOP?

XML 기반의 Spring AOP는 JDK 버젼이랑 관계 없이 사용할 수 있다는 장점이 있으며 설정 파일을 보고 aspect가 적용된 상태를 파악할 수 있습니다. 하지만 필요한 정보를 두 곳에 나눠 놓는 다는 점에서 DRY(Don't Repeat Youeself) 원칙을 어긴다고 볼 수 있습니다. @AspectJ 에서는 && || ! 를 사용하여 포인트컷 끼리의 연산을 할 수가 있었는데 그걸 못합니다.

5.0 미만의 JDK를 사용해야 한다면 스키마 기반 Spring AOP를 사용하시고(유일한 선택 사항이죠.) 5.0 이상일 때 단순한 설정(예를 들어 선언적 트랙잭션 관리 같은 것) 이외에 애스팩트가 필요하다면 @AspectJ 를 사용하는게 좋겠습니다.

예제 만들면서 써보니까 전 @AspectJ가 훨씬 편하더군요.



top

Write a comment.


Schema 기반 Introduction

Spring/Chapter 6 : 2007.04.06 12:29


Introduction 예제 와 동일한 예제입니다. <aop:declare-parents> 를 사용하였다는 것만 다르죠. 흐흣;;

새로 추가할 메소드를 가진 인터페이스와 그것을 구현한 클래스르 만듭니다.

public interface TicketTracked {
    void incrementTicketCount();
}

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

그리고 this()를 사용하여 포인트컷을 만들어 줍니다.

<aop:pointcut id="countTicket"
            expression="execution(* sell*(..)) and this(ticketTracked)"/>

다음 이 포인트 컷을 사용할 introduction을 설정해 줍니다. 이 설정은 <aop:aspect> 바로 아래에 있어야 합니다. 안그럼 에러나 나더군요~
<aop:declare-parents
                types-matching="aop.newStyle.domain.KeesunCinema"
                implement-interface="aop.newStyle.aspect.TicketTracked"
                default-impl="aop.newStyle.aspect.TicketTrackedImpl" />
<aop:after method="ticketTtrack" pointcut-ref="countTicket"/>

그리고 테스트를 해보면 원하는 결과를 확인할 수 있습니다.
    @Test
    public void sellTicket() {
        cinema.sellTicket(movie, new Date());
    }

어서 오세요. 무엇을 도와드릴까요?
어서 오세요. 무엇을 도와드릴까요?
왔어? 영화 뭐 볼껀데?
하이 공공의적보려고?
표 1 장 팔았다.
감사합니다. 공공의적을 구매 하셨습니다.
쌩큐  공공의적잘봐!
top

Write a comment.


Schema 기반 Advice parameters

Spring/Chapter 6 : 2007.04.06 12:09


Advice parameters 여기서 살펴봤던 것과 거의 동일합니다. args() 표현식을 사용하여 포인트컷을 정의합니다.

<aop:pointcut id="sellTicket2" expression="execution(* sell*(..)) and args(movie,..)"/>

movie라는 이름의 파라미터를 받는 메소드의 조인포인트를 가리키게 됩니다. 이걸 받아서 처리할 어드바이스를 만듭니다.

    public void veryWelcome(Movie movie){
        System.out.println("하이 " + movie.getName() + "보려고?");
    }

xml 파일에 설정해 줍니다.

<aop:aspect id="cinema" ref="aspect">
            <aop:before method="welcome" pointcut-ref="sellTicket" />
            <aop:before method="welcome" pointcut-ref="sellTicket" />
            <aop:after-returning method="afterSellTicket" pointcut-ref="sellTicket" returning="ticket"/>
            <aop:around method="aroundSellTicket" pointcut-ref="sellTicket"/>
            <aop:before method="veryWelcome" pointcut-ref="sellTicket2" arg-names="movie"/>
</aop:aspect>

args-names에 넣어준 값 movie는 어드바이스 역할을 하는 메소드에서 받는 메개변수 이름입니다. 테스트를 실행하면 원하던 결과를 확인할 수 있습니다.
    @Test
    public void sellTicket() {
        cinema.sellTicket(movie, new Date());
    }

어서 오세요. 무엇을 도와드릴까요?
어서 오세요. 무엇을 도와드릴까요?
왔어? 영화 뭐 볼껀데?
하이 공공의적보려고?
감사합니다. 공공의적을 구매 하셨습니다.
쌩큐  공공의적잘봐!

before중에서 가장 마지막이고 around에서 pjp.proceed 이전에 수행하는 작업을 before로 보면 예상할 수 있는 위치에 수행된 걸 확인할 수 있습니다.
top

Write a comment.


<aop:around> 어드바이스 예제

Spring/Chapter 6 : 2007.04.06 11:44


around 어드바이스 역할을 메소드를 만듭니다. @Around 어드바이스 예제 의 예제와 거의 동일합니다.

메소드의 첫번째 인자로 ProceedingJoinPoint가 와야 하며 throws Throwable을 붙여줍니다.
    public Object aroundSellTicket(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println("왔어? 영화 뭐 볼껀데?");
        Ticket ticket = (Ticket) pjp.proceed();
        System.out.println("쌩큐  " + ticket.getMovie().getName() + "잘봐!");
        return ticket;
    }

xml 설정 파일에 aound 어드바이스를 설정해 줍니다.

<aop:aspect id="cinema" ref="aspect">
            <aop:before method="welcome" pointcut-ref="sellTicket" />
            <aop:before method="welcome" pointcut-ref="checkTicket" />
            <aop:after-returning method="afterSellTicket" pointcut-ref="sellTicket" returning="ticket"/>
            <aop:around method="aroundSellTicket" pointcut-ref="sellTicket"/>
</aop:aspect>

테스트를 실행합니다.
    @Test
    public void sellTicket() {
        cinema.sellTicket(movie, new Date());
    }

어서 오세요. 무엇을 도와드릴까요?
왔어? 영화 뭐 볼껀데?
감사합니다. 공공의적을 구매 하셨습니다.
쌩큐  공공의적잘봐!

이 전에 사용했던 예제의 어드바이스가 같이 적용이 됐기 때문에 결과가 저러헤게 나왔습니다. 어드바이스가 적용되는 순서는 Advice ordering 여기서도 살펴봤지만 간단하게 aspect에 등록되어 있는 순이라고 생각해도 될 것 같습니다.


top

Write a comment.


<aop:after-returning> 어드바이스에서 리턴값 받아오기

Spring/Chapter 6 : 2007.04.06 11:33


Aspect 역할을 할 클래스(이름을 Aspect로 했습니다. 꼭 그래야 하는건 아니죠;;)에 After Returning 때 weaving 될 어드바이스를 일반 메소드로 정의합니다.

public class Aspect {

    public void welcome(){
        System.out.println("어서 오세요. 무엇을 도와드릴까요?");
    }

    public void confirm(){
        System.out.println("확인하기");
    }

    public void afterSellTicket(Ticket ticket){
        System.out.println("감사합니다. " + ticket.getMovie().getName() + "을 구매 하셨습니다.");
    }
}

그리고 설정파일에 어드바이스를 등록합니다.

<aop:aspect id="cinema" ref="aspect">
            <aop:before method="welcome" pointcut-ref="sellTicket" />
            <aop:before method="welcome" pointcut-ref="checkTicket" />
            <aop:after-returning method="afterSellTicket" pointcut-ref="sellTicket" returning="ticket"/>
</aop:aspect>

@AfterReturning 어드바이스 만들기 이것과 거의 동일한 예제입니다. 결과는 무난히 리턴값을 가져온 것을 확인할 수 있습니다.

    @Test
    public void sellTicket() {
        cinema.sellTicket(movie, new Date());
    }

어서 오세요. 무엇을 도와드릴까요?
감사합니다. 공공의적을 구매 하셨습니다.
top

Write a comment.


Schema 기반 Spring AOP 포인트컷 만들 때 주의 할 것

Spring/Chapter 6 : 2007.04.06 09:01


<aop:config>

        <aop:pointcut id="sellTicket"
            expression="execution(* sell*(..))" />

        <aop:aspect id="cinema" ref="aspect">

            <aop:pointcut id="sellTicket2"
                expression="execution(* sell*(..))" />

            <aop:pointcut id="sellTicket3"
                expression="execution(* sell*(..))" />

            <aop:before method="welcome" pointcut-ref="sellTicket" />

            <aop:before method="welcome" pointcut-ref="sellTicket2" />

        </aop:aspect>

    </aop:config>

<aop:aspect> 태그 안에 pointcut 정의는 하나밖에 올 수가 없습니다. 안그럼 어제 아침에 적었던 'Schema 기반 Spring AOP 희한한 것'에서 보았던 에러가 발생합니다.

대신 <aop:config> 태그 아래 <aop:aspect> 태그 밖에 정의를 하면 여러개를 정의할 수 있습니다.

<aop:config>

        <aop:pointcut id="sellTicket"
            expression="execution(* sell*(..))" />

        <aop:pointcut id="sellTicket2"
            expression="execution(* sell*(..))" />

        <aop:aspect id="cinema" ref="aspect">

            <aop:pointcut id="sellTicket3"
                expression="execution(* sell*(..))" />

            <aop:before method="welcome" pointcut-ref="sellTicket" />

            <aop:before method="welcome" pointcut-ref="sellTicket2" />

        </aop:aspect>

    </aop:config>

즉 이렇게 만들면 에러 없이 잘 돌아갑니다. aspect 안에는 최대 하나밖에 허용하지 않고 (물론 in-line 포인트컷을 만들면 여러 개의 포인트컷을 사용할 순 있습니다.) config 안에는 여러개가 있어도 되는 걸 알 수 있습니다.

아무래도 config에서 만드는 포인트컷들은 다른 애스팩트의 어드바이스들에서 사용할 것이기 때문에 독립적으로 여러개 존재 하도록 한 것 같습니다.

여기서 드러나는 스키마 기반 Spring AOP의 불편한 점
1. @AspectJ 에서는 하나의 애스팩트 내부에 여러 포인트컷이 존재할 수 있는 것과 매칭이 되지 않아 혼란스럽습니다.
2. @AspectJ에는 없는 config 라는 영역이 존재해서 혼란스럽습니다.
3. 더군다나 @AspectJ에서 포인트컷끼리 연산을 할 때 사용한 &&, ||, ! 을 사용할 수 없다는 것도 불편합니다.

top

Write a comment.


Schema 기반 Spring AOP 희한한 것

Spring/Chapter 6 : 2007.04.05 08:47


    <aop:config>
        <aop:aspect id="cinema" ref="aspect">
            <aop:pointcut id="sellTicket" expression="execution(* sell*(..))" />
            <aop:before method="welcome" pointcut-ref="sellTicket" />
            <aop:before method="welcome" pointcut="execution(* sell*(..))"/>
        </aop:aspect>
    </aop:config>

이렇게 포인트컷 하나, 어드바이스 다수 일 경우에는 실행이 되는데요.
    <aop:config>
        <aop:aspect id="cinema" ref="aspect">
            <aop:pointcut id="sellTicket" expression="execution(* sell*(..))" />
            <aop:before method="welcome" pointcut-ref="sellTicket" />

            <aop:pointcut id="sellTicket2" expression="execution(* sell*(..))" />
            <aop:before method="welcome" pointcut-ref="sellTicket2" />
        </aop:aspect>
    </aop:config>

이렇게 포인트컷이 둘 이상일 경우에는 에러가 발생합니다.
org.springframework.beans.factory.BeanDefinitionStoreException: Line 42 in XML document from class path resource [aop/newStyle/schemaConfiguration.xml] is invalid; nested exception is org.xml.sax.SAXParseException: cvc-complex-type.2.4.a: Invalid content was found starting with element 'aop:pointcut'. One of '{"http://www.springframework.org/schema/aop":before, "http://www.springframework.org/schema/aop":after, "http://www.springframework.org/schema/aop":after-returning, "http://www.springframework.org/schema/aop":after-throwing, "http://www.springframework.org/schema/aop":around}' is expected.

흠...in-line 포인트컷은 되는데 왜 그냥 포인트컷은 하나밖에 못쓸까요. 희한하군요.
top

Write a comment.


초간단 Schema 기반 Spring AOP

Spring/Chapter 6 : 2007.04.05 08:37


먼저 Aspect 역할을 할 클래스를 만듭니다. 어드바이스를 메소드로 정의해 둘 클래스입니다.

public class Aspect {

    public void welcome(){
        System.out.println("어서 오세요. 무엇을 도와드릴까요?");
    }
}

이제 xml 설정파일로 가서 이 클래스를 빈으로 등록을 하고 어스팩트를 만들 때 사용하도록 합니다.

    <!-- aop -->
    <bean id="aspect" class="aop.newStyle.aspect.Aspect" />

    <aop:config>
        <aop:aspect id="cinema" ref="aspect">
            <aop:pointcut id="sellTicket"
                expression="execution(* sell*(..))" />
            <aop:before method="welcome" pointcut-ref="sellTicket" />
        </aop:aspect>
    </aop:config>

포인트컷 표현식은 이전 @AspectJ 에서와 동일하게 사용할 수 있습니다.

    @Test
    public void sellTicket() {
        cinema.sellTicket(movie, new Date());
    }

다음과 같이 대상이 되는 메소드를 호출 하면 맨 위에 만든 애스팩트에 있는 메소드 중에서 advice에 등록한 메소드가 실행됩니다.
top

Write a comment.


6.3. Schema-based AOP support

Spring/Chapter 6 : 2007.04.01 23:32


Java 5 를 사용하지 못하거나 단순히 XML 설정을 좋아하는 분들은 스키마 기반의 AOP 설정을 사용하여 @AspectJ에서 했던 모든 것을 할 수 있습니다.

단 aop 네임스페이스를 사용하기 위해서는 설정 파일로 스키마 기반의 XML 파일을 사용해야 합니다.
<!-- XML Schema-style -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

<!-- <bean/> definitions here -->

</beans>

aop 설정은 모두 <aop:config> </aop:config> 안에 들어가야 하며 이 태그는 <beans> </beans> 내부에서 여러 번 사용할 수 있습니다.

초간단 Schema 기반 Spring AOP

6.3.1. Declaring an aspect

aspect는 일반 클래스로써 그냥 bean으로 등록을 해둡니다. 포인트컷과 어드바이스에 대한 정보는 XML로 나타낼 수 있습니다.

포인트 컷은 @Pointcut의 표현식을 그대로 xml 설정에 적어 주면 되고, advice로 사용할 메소드의 이름을 역시 xml에 적어 주면 될 것 같습니다.

어찌됐든 aspect 역할을 할 bean을 <aop:config> 안에 <aop:aspect> 태그의 ref 속성으로 정의합니다.

Schema 기반 Spring AOP 희한한 것
Schema 기반 Spring AOP 포인트컷 만들 때 주의 할 것

6.3.2. Declaring a pointcut

pointcut은 <aop:config> 또는 <aop:aspect> 태그 안에 <aop:pointcut> 태그를 사용하여 정의할 수 있습니다.

<aop:aspect> 로 정의하면 그 aspect 내에서만 사용할 수 있으며 <aop:config> 바로 하위에 정의하면 여러 aspect에서 사용할 수 있습니다.

6.3.3. Declaring advice

@AspectJ 에서 사용 할 수 있었던 다섯 가지의 Advice 모두 정의할 수 있습니다.
<aop:after-returning> 어드바이스에서 리턴값 받아오기
<aop:around> 어드바이스 예제
Schema 기반 Advice parameters

6.3.4. Introductions

<aop:declare-parents> 를 사용합니다.

<aop:declare-parents
      types-matching="com.xzy.myapp.service.*+",
      implement-interface="UsageTracked"
      default-impl="com.xyz.myapp.service.tracking.DefaultUsageTracked"/>
 
  <aop:before
    pointcut="com.xyz.myapp.SystemArchitecture.businessService()
              and this(usageTracked)"
    method="recordUsage"/>

Schema 기반 Introduction

6.3.5. Aspect instantiation models

스키마 기반에서 제공되는 건 singleton 모델 뿐이고 차후에 나머지도 제공될 예정입니다. 앞에서 살펴봤던 @Aspect 기반에서는 perTarget(singleton) 또는 perThis(peototype) 속성을 사용하여 선택할 수 있었습니다.

6.3.6. Advisors

Advisor 컨셉은 Spring 1.2에서 왔으며 AspectJ에 있는 개념은 아닙니다. AspectJ 스타일의 Pointcut 표현식을 사용할 수 있다는 장점이 있으며 Advisor에서 합 칠 Advice bean은 반드시 이전 유형의 Advice들이 구현해야 했던 인터페이스들을 구현하고 있어야 합니다.

6.3.7. Example

이전 글
의 예제를 스키마 기반으로 다시 작성합니다.

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