5.5.3 Advice 선언 by sh

5.5.3. Advice 선언

스키마 기반 AOP 지원은 @AspectJ 스타일과 동일한 5 가지 유형의 조언을 사용하며 정확히 동일한 의미를 갖습니다.

Before Advice

Before advice는 일치하는 메소드 실행 전에 동작합니다. 다음 예제와 같이 <aop:before>요소를 사용하여 <aop:aspect>내부에서 선언됩니다.

<aop:aspect id="beforeExample" ref="aBean">

    <aop:before
        pointcut-ref="dataAccessOperation"
        method="doAccessCheck"/>

    ...

</aop:aspect>

여기서 dataAccessOperation은 최상위 (<aop:config>) 수준에서 정의 된 pointcut의 id입니다. 대신 pointcut 인라인을 정의하려면 다음과 같이 pointcut-ref속성을 pointcut속성으로 대체하십시오.

<aop:aspect id="beforeExample" ref="aBean">

    <aop:before
        pointcut="execution(* com.xyz.myapp.dao.*.*(..))"
        method="doAccessCheck"/>

    ...

</aop:aspect>

@AspectJ 스타일에 대한 논의에서 언급했듯이, 명명 된 pointcuts를 사용하면 코드의 가독성을 크게 향상시킬 수 있습니다.

method속성은 advice의 body를을 제공하는 메소드 (doAccessCheck)를 식별합니다. 이 메소드는 어드바이스가 포함 된 aspect 요소에 의해 참조 된 bean에서 정의되어야합니다. 데이터 액세스 작업이 실행되기 전에 (pointcut 표현식과 일치하는 메소드 실행 join point), aspect bean에 대한 doAccessCheck메소드가 호출됩니다.

After Returning Advice

Returning advice는 일치하는 메소드 실행이 정상적으로 완료 될 때 실행됩니다. before advice와 같은 방법으로 <aop:aspect>내부에 선언됩니다. 다음 예제에서는 이를 선언하는 방법을 보여줍니다.

<aop:aspect id="afterReturningExample" ref="aBean">

    <aop:after-returning
        pointcut-ref="dataAccessOperation"
        method="doAccessCheck"/>

    ...

</aop:aspect>

@AspectJ 스타일에서와 마찬가지로, advice body 내에서 반환 값을 얻을 수있습니다. 이렇게하려면 다음 예제와 같이 반환 값을 전달해야하는 매개 변수의 이름을 지정하기 위해 returning 속성을 사용합니다.

<aop:aspect id="afterReturningExample" ref="aBean">

    <aop:after-returning
        pointcut-ref="dataAccessOperation"
        returning="retVal"
        method="doAccessCheck"/>

    ...

</aop:aspect>

doAccessCheck메소드는 retVal이라는 매개 변수를 선언해야합니다. 이 매개 변수의 유형은 @AfterReturning에 대해 설명한 것과 같은 방식으로 일치를 제한합니다. 예를 들어, 다음과 같이 메소드 서명을 선언 할 수 있습니다.

public void doAccessCheck(Object retVal) {...

After Throwing Advice

예외를 throw하여 일치하는 메소드 실행이 종료 될 때 advice를 실행 한 후 실행합니다. 다음 예제와 같이 after-throwing 요소를 사용하여 <aop:aspect>내부에서 선언됩니다.

<aop:aspect id="afterThrowingExample" ref="aBean">

    <aop:after-throwing
        pointcut-ref="dataAccessOperation"
        method="doRecoveryActions"/>

    ...

</aop:aspect>

@AspectJ 스타일에서와 마찬가지로, advice body 내에서 던져진 예외를 얻을 수있다. 그렇게하려면 throwing 속성을 사용하여 다음 예제와 같이 예외를 전달해야하는 매개 변수의 이름을 지정합니다.

<aop:aspect id="afterThrowingExample" ref="aBean">

    <aop:after-throwing
        pointcut-ref="dataAccessOperation"
        throwing="dataAccessEx"
        method="doRecoveryActions"/>

    ...

</aop:aspect>

doRecoveryActions메소드는 dataAccessEx라는 매개 변수를 선언해야합니다. 이 매개 변수의 유형은 @AfterThrowing에 대해 설명한 것과 같은 방식으로 일치를 제한합니다. 예를 들어, 메소드 서명은 다음과 같이 선언 될 수 있습니다.

public void doRecoveryActions(DataAccessException dataAccessEx) {...

After (Finally) Advice

매치 된 메소드 실행이 어떻게 종료 되더라도 (최후에내) advice가 실행된다. 다음 예제와 같이 after 요소를 사용하여 선언 할 수 있습니다.

<aop:aspect id="afterFinallyExample" ref="aBean">

    <aop:after
        pointcut-ref="dataAccessOperation"
        method="doReleaseLock"/>

    ...

</aop:aspect>

Around Advice

마지막 advice는 around advice 입니다. around advice는 매치 메소드 실행을 '둘러싼'다. 메소드가 실행되기 전과 후에 모두 작업을 수행 할 수있는 기회를 가지며 메소드가 실제로 실행될시기, 방법 및 방법을 결정합니다. around advice는 스레드 안전 방식으로 메서드 실행 전후의 상태를 공유하는 데 자주 사용됩니다 (예 : 타이머 시작 및 중지). 항상 귀하의 요구 사항을 충족시키는 가장 강력한 형태의 advice를 사용하십시오. before advice가 그 일을 할 수 있다면 around advice를 사용하지 마십시오.

메소드 실행 전 후 익셉션 모두 처리 가능!

aop:around 요소를 사용하여 around advice를 선언 할 수 있습니다. advice 메소드의 첫 번째 매개 변수는 ProceedingJoinPoint유형이어야 합니다. advice body에서 ProceedingJoinPoint에서 proceed()를 호출하면 기본 메서드가 실행됩니다. proceed메서드는 Object[]를 사용하여 호출 할 수도 있습니다. 배열의 값은 진행될 때 메서드 실행에 대한 인수로 사용됩니다. 호출 시 Object[]proceed를 호출하는 것에 대해 알아보려면 Around Advice를 참고하십시오. 다음 예는 XML에서 around advice를 선언하는 방법을 보여줍니다.

  • proceed()를 기준으로 위의 소스는 before, 아래의 소스는 afterThrowing 로 구분 지어질 수 있다.

  • proceed() 의 리턴 값은 Object 이다. 이는 Aspect 로 연결된 Original Method 의 리턴 값을 받을 수 있다. ( 형 변환 )

<aop:aspect id="aroundExample" ref="aBean">

    <aop:around
        pointcut-ref="businessService"
        method="doBasicProfiling"/>

    ...

</aop:aspect>

doBasicProfilingadvice의 구현은 다음 예제처럼 @AspectJ 예제와 똑같을 수있다 (물론 주석을 제외하고).

public Object doBasicProfiling(ProceedingJoinPoint pjp) throws Throwable {
    // start stopwatch
    Object retVal = pjp.proceed();
    // stop stopwatch
    return retVal;
}

Advice Parameters

스키마 기반 선언 스타일은 @AspectJ 지원에 대해 설명한 것과 동일한 방식으로 완전히 입력 된 조언을 지원합니다. 즉, 포인트 메서드 매개 변수를 이름으로 advice 메서드 매개 변수에 일치시킵니다. 자세한 내용은 Advice Parameters를 참조하십시오. 앞서 설명한 검색 방법에 의존하지 않고 advice 메소드에 대한 인수 이름을 명시 적으로 지정하려면 argNames속성과 동일한 방식으로 처리되는 advice 요소의 arg-names 속성을 사용하면됩니다 조언 주석에서 (Determining Argument Names에 설명 된대로). 다음 예제에서는 XML에서 인수 이름을 지정하는 방법을 보여줍니다.

<aop:before
    pointcut="com.xyz.lib.Pointcuts.anyPublicMethod() and @annotation(auditable)"
    method="audit"
    arg-names="auditable"/>

arg-names 속성은 매개 변수 이름의 쉼표로 구분 된 목록을 허용합니다.

XSD 기반 접근 방식의 약간 더 관여 된 다음 예는 강하게 유형화 된 여러 매개 변수와 함께 사용되는 몇 가지 around advice를 보여줍니다.

package x.y.service;

public interface PersonService {

    Person getPerson(String personName, int age);
}

public class DefaultFooService implements FooService {

    public Person getPerson(String name, int age) {
        return new Person(name, age);
    }
}

다음은 aspect 입니다. profile(..) 메소드는 강력한 형식의 매개 변수를 여러 개 허용하며, 그 중 첫 번째는 메소드 호출을 진행하는 데 사용되는 조인 포인트입니다. 이 매개 변수가 있으면 다음 예제와 같이 profile(..)aroundadvice로 사용된다는 표시입니다.

package x.y;

import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.util.StopWatch;

public class SimpleProfiler {

    public Object profile(ProceedingJoinPoint call, String name, int age) throws Throwable {
        StopWatch clock = new StopWatch("Profiling for '" + name + "' and '" + age + "'");
        try {
            clock.start(call.toShortString());
            return call.proceed();
        } finally {
            clock.stop();
            System.out.println(clock.prettyPrint());
        }
    }
}

마지막으로, 다음 예제 XML 구성은 특정 조인 포인트에 대한 선행 조언의 실행에 영향을줍니다.

<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.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- this is the object that will be proxied by Spring's AOP infrastructure -->
    <bean id="personService" class="x.y.service.DefaultPersonService"/>

    <!-- this is the actual advice itself -->
    <bean id="profiler" class="x.y.SimpleProfiler"/>

    <aop:config>
        <aop:aspect ref="profiler">

            <aop:pointcut id="theExecutionOfSomePersonServiceMethod"
                expression="execution(* x.y.service.PersonService.getPerson(String,int))
                and args(name, age)"/>

            <aop:around pointcut-ref="theExecutionOfSomePersonServiceMethod"
                method="profile"/>

        </aop:aspect>
    </aop:config>

</beans>

다음의 driver 스크립트를 참고하십시오.

import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import x.y.service.PersonService;

public final class Boot {

    public static void main(final String[] args) throws Exception {
        BeanFactory ctx = new ClassPathXmlApplicationContext("x/y/plain.xml");
        PersonService person = (PersonService) ctx.getBean("personService");
        person.getPerson("Pengo", 12);
    }
}

Boot 클래스를 사용하면 표준 출력에서 ​​다음과 비슷한 결과를 얻을 수 있습니다.

StopWatch 'Profiling for 'Pengo' and '12'': running time (millis) = 0
-----------------------------------------
ms     %     Task name
-----------------------------------------
00000  ?  execution(getFoo)

Advice Ordering

여러 advice가 동일한 조인 포인트 (실행 메소드)에서 실행되어야하는 경우 주문 규칙은 Advice Ordering에 설명되어 있습니다. aspect 간의 우선 순위는 aspect를 뒷받침하는 bean에 Order주석을 추가하거나 bean이 Ordered 인터페이스를 구현하도록함으로써 결정됩니다.

Last updated