> For the complete documentation index, see [llms.txt](https://wannaqueen.gitbook.io/spring5/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://wannaqueen.gitbook.io/spring5/spring-5.0/5-spring-aspect/5.5/5.5.3-by-sh.md).

# 5.5.3 Advice 선언 by sh

### **5.5.3. Advice 선언**

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

**Before Advice**

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

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

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

    ...

</aop:aspect>
```

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

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

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

    ...

</aop:aspect>
```

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

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

**After Returning Advice**

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

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

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

    ...

</aop:aspect>
```

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

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

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

    ...

</aop:aspect>
```

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

```java
public void doAccessCheck(Object retVal) {...
```

**After Throwing Advice**

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

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

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

    ...

</aop:aspect>
```

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

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

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

    ...

</aop:aspect>
```

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

```java
public void doRecoveryActions(DataAccessException dataAccessEx) {...
```

**After (Finally) Advice**

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

```markup
<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를 사용하지 마십시오.**&#x20;

{% hint style="info" %}
메소드 실행 전 후 익셉션 모두 처리 가능!
{% endhint %}

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

{% hint style="info" %}

* proceed()를 기준으로 위의 소스는 before, 아래의 소스는 afterThrowing 로 구분 지어질 수 있다.
* proceed() 의 리턴 값은 Object 이다. 이는 Aspect 로 연결된 Original Method 의 리턴 값을 받을 수 있다. ( 형 변환 )
  {% endhint %}

![](/files/-LaxuBXFiLCL8Y97ZbQT)

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

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

    ...

</aop:aspect>
```

`doBasicProfiling`advice의 구현은 다음 예제처럼 @AspectJ 예제와 똑같을 수있다 (물론 주석을 제외하고).&#x20;

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

**Advice Parameters**

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

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

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

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

```java
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(..)`이 `around`advice로 사용된다는 표시입니다.&#x20;

```java
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 구성은 특정 조인 포인트에 대한 선행 조언의 실행에 영향을줍니다.&#x20;

```markup
<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 스크립트를 참고하십시오.

```java
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](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-ataspectj-advice-ordering)에 설명되어 있습니다. aspect 간의 우선 순위는 aspect를 뒷받침하는 bean에 `Order`주석을 추가하거나 bean이 Ordered 인터페이스를 구현하도록함으로써 결정됩니다.&#x20;
