Whiteship's Note


6.6. Proxying mechanisms

Spring/Chapter 6 : 2007.04.06 14:11


Spring AOP는 JDK의 Dynamic Proxy 또는 CGLib을 사용하여 프록시를 만듭니다. 타겟이 되는 객체가 인터페이스를 하나라도 구현했다면 JDK의 Proxy를 사용할 것이고 구현한 인터페이스가 하나도 없을 경우에는 CGLib을 사용하게 됩니다. 원할 때는 명시적으로 CGLib을 사용하도록 할 수도 있지만 다음의 제약사항들이 있습니다.

1. final 메소드는 어드바이스가 적용되지 않습니다. - 오버라이딩 못하기 때문이죠.
2. CGLIB 라이러리가 추가로 필요합니다. - spring이 알려줄 겁니다.
3. 생성자가 두 번 호출 됩니다. - 상속해서 만든거니깐 그렇겠죠.

명시적으로 CGLIB을 사용하고 싶을 땐 다음 처럼 설정해 줍니다.

@AspectJ 기반
<aop:aspectj-autoproxy proxy-target-class="true"/>

Schema 기반
<aop:config proxy-target-class="true">  
</aop:config>

6.6.1. Understanding AOP proxies

사용자 삽입 이미지
일반적인 객체에 대한 호출을 그림으로 표현한 것입니다.

사용자 삽입 이미지
이건 프록시 객체를 호출했을 떄를 그림으로 표현한 것입니다. 프록시에 있는 foo()를 먼저 하고 그 다음에 타겟 객체의 foo()를 호출하고 있습니다.

이때 self-invocation issue가 발생합니다. 소스 코드로 확인 하는게 좋겠습니다.

public interface Pojo {
    public void foo();
    public void bar();
}

public class SimplePojo implements Pojo {
    public void foo(){
        System.out.println("this is foo and call bar()");
        bar();
    }
    public void bar() {
        System.out.println("this is bar");
    }
}

인터페이스와 타겟이 될 클래스가 있으며 이것을 프록시팩토리를 사용하여 apsect를 만들고 간단한 어드바이스를 추가합니다.

    @Test
    public void name() {
        ProxyFactory factory = new ProxyFactory(new SimplePojo());
        factory.addInterface(Pojo.class);
        factory.addAdvice(new RetryAdvice());

        Pojo pojo = (Pojo) factory.getProxy();
        pojo.foo();
    }

추가한 어드바이스는 다음과 같습니다.

    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        System.out.println("Before Adivce");
    }

테스트를 실행하면 결과는 다음과 같습니다.

Before Adivce
this is foo and call bar()
this is bar

원하던 결과는 이게 아니죠. 원래는 다음 처럼 나와야 합니다.

Before Adivce
this is foo and call bar()
Before Adivce
this is bar

어드바이스가 타겟에 적용되었고 별다른 포인트컷 표현식을 쓰지 않았기 떄문에 모든 메소드에 적용이 되어야 합니다. foo()를 호출 했고 foo()에서 bar()를 호출 했기 때문에 bar()를 호출 할 때도 적용이 됐어야 하는데 그렇치 않았습니다.

프록시 객체를 지나서 타겟 객체에 다다른 뒤에 타겟 객체에서 자기 자신의 메소드를 호출 할 때는 프록시를 거치지 않기 때문에 이렇게 됩니다. 이걸 self-invocation issue 라고 합니다.

이 이슈의 해결 방법은.. 다소 invasive 하지만 어쩔 수 없이 다음 처럼 프록시를 통해서 호출하도록 코드를 수정해야 합니다.

public class SimplePojo implements Pojo {
    public void foo(){
        System.out.println("this is foo and call bar()");
        ((Pojo) AopContext.currentProxy()).bar();
    }

    public void bar() {
        System.out.println("this is bar");
    }
}

레퍼런스에는 조금 메소드가 다르더군요. 레퍼런스에 오타도 있고 메소드 이름도 잘못 되어 있었지만 이클립스가 도와주고 있기 때문에 쉽게 고쳐 쓸 수 있었습니다.

    @Test
    public void name() {
        ProxyFactory factory = new ProxyFactory(new SimplePojo());
        factory.addInterface(Pojo.class);
        factory.addAdvice(new RetryAdvice());
        factory.setExposeProxy(true);
        Pojo pojo = (Pojo) factory.getProxy();
        pojo.foo();
    }
신고
top


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


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


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


<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


<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


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


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


초간단 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


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


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


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 이 클래스라는 걸 확인할 수 있습니다.

more..


@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이 발생하는데 아직 원인을 모르겠습니다. 레퍼런스에 나와있는 코드와 똑같이 친것 같은데 말이죠. ㅠ.ㅠ

more..


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


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


@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


@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


@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


@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


초간단 @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


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


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 모두 정의할 수 있습니다.

more..

<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


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


Aspect Oriented Programming with Spring

Spring/Chapter 6 : 2007.03.26 21:23


6.1. Introduction
AOP의 기본 개념과 Spring AOP의 기능과 목표를 이야기 합니다.
Spring AOP는 Proxy 기반입니다.

6.1. Introduction

6.2. @AspectJ support
어노테이션을 사용하여 AspectJ를 사용하는 방법입니다.
Spring AOP가 지원하는 포인트컷은 method 실행 시점뿐입니다.

6.2. @AspectJ support

6.3. Schema-based AOP support
6.2에서 한 내용을 어노테이션 기반이 아닌 XML에 설정을 사용하는 방법 도 있습니다.

6.3. Schema-based AOP support

6.4. Choosing which AOP declaration style to use
어노테이션을 사용할 것인가? XML 설정을 사용할 것인가?
Spring AOP를 사용할 것인가? AspectJ를 사용할 것인가?

6.4. Choosing which AOP declaration style to use

6.5. Mixing aspect types

어노테이션을 사용하는 방법과 XML 설정을 사용하는 방법을 섞어서 사용할 수 있습니다. 심지어 Spring 1.2 버젼 스타일의 프록시와도 같이 사용할 수 있습니다.

6.6. Proxying mechanisms
JDK 프록시 또는 CGLIB을 사용하는데요. 어떤 인터페이스도 구현하지 않았다면 CGLIB 프록시를 사용하고 그렇지 않은 경우에는 JDK 프록시를 사용합니다.

6.6. Proxying mechanisms

6.7. Programmatic creation of @AspectJ Proxies

AspectJProxyFactory를 사용하여 직접 프록시 클래스를 만들 수 있습니다.

6.8. Using AspectJ with Spring applications

AspectJ의 위버와 컴파일러를 사용할 수 있습니다.

6.9. Further Resources

AspectJ home page 여기서 더 많은 내용을 참조 할 수 있습니다.
신고

'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







티스토리 툴바