> 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.7-by-sh.md).

# 5.5.7 AOP 스키마 예제 by sh

### **5.5.7. AOP 스키마 예제**

이 절에서는 [An AOP Example](https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#aop-ataspectj-example)의 동시 잠금 실패 재시도 예제가 스키마 지원으로 다시 작성 될 때 어떻게 표시되는지 보여줍니다.&#x20;

비즈니스 서비스의 실행은 동시성 문제 (예 : 교착 상태 실패자)로 인해 때때로 실패 할 수 있습니다. 작업이 다시 시도되면 다음 시도에서 성공할 수 있습니다. 그러한 조건 (충돌 해결을 위해 사용자에게 다시 돌아갈 필요가없는 멱등 원 (itempotent) 작업)에서 다시 시도하는 것이 적합한 비즈니스 서비스의 경우 클라이언트가 `PessimisticLockingFailureException`을 보지 않도록 작업을 투명하게 다시 시도해야 합니다. 이는 서비스 계층의 여러 서비스를 명확히 차단하는 요구 사항이므로 aspect 통한 구현에 이상적입니다.&#x20;

`proceed`를 여러 번 호출 할 수 있도록 around advice을 사용해야합니다. 다음 목록은 기본 aspect 구현 (스키마 지원을 사용하는 일반적인 Java 클래스)을 보여줍니다.&#x20;

```java
public class ConcurrentOperationExecutor implements Ordered {

    private static final int DEFAULT_MAX_RETRIES = 2;

    private int maxRetries = DEFAULT_MAX_RETRIES;
    private int order = 1;

    public void setMaxRetries(int maxRetries) {
        this.maxRetries = maxRetries;
    }

    public int getOrder() {
        return this.order;
    }

    public void setOrder(int order) {
        this.order = order;
    }

    public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
        int numAttempts = 0;
        PessimisticLockingFailureException lockFailureException;
        do {
            numAttempts++;
            try {
                return pjp.proceed();
            }
            catch(PessimisticLockingFailureException ex) {
                lockFailureException = ex;
            }
        } while(numAttempts <= this.maxRetries);
        throw lockFailureException;
    }

}
```

aspect는 `Ordered`인터페이스를 구현하여 aspect의 우선 순위를 트랜잭션 advice 보다 높게 설정할 수 있습니다 (우리는 재 시도 할 때마다 새로운 트랜잭션을 원합니다). `maxRetries`및 `order`속성은 모두 스프링에 의해 구성됩니다. 주요 동작은 `doConcurrentOperation`around advice 메소드에서 발생합니다. 우리는 계속 하려고합니다. `PessimisticLockingFailureException`으로 실패하면 재 시도를 모두 마쳤으면 다시 시도합니다.&#x20;

| 이 클래스는 @AspectJ 예제에서 사용 된 것과 동일하지만 Annotation이 제거 된 클래스입니다. |
| ----------------------------------------------------------- |

해당 스프링 설정은 다음과 같습니다.

```markup
<aop:config>

    <aop:aspect id="concurrentOperationRetry" ref="concurrentOperationExecutor">

        <aop:pointcut id="idempotentOperation"
            expression="execution(* com.xyz.myapp.service.*.*(..))"/>

        <aop:around
            pointcut-ref="idempotentOperation"
            method="doConcurrentOperation"/>

    </aop:aspect>

</aop:config>

<bean id="concurrentOperationExecutor"
    class="com.xyz.myapp.service.impl.ConcurrentOperationExecutor">
        <property name="maxRetries" value="3"/>
        <property name="order" value="100"/>
</bean>
```

당분간은 모든 비즈니스 서비스가 멱등수라고 가정합니다. 그렇지 않은 경우 다음 예처럼 `Idempotent`주석을 도입하고 주석을 사용하여 서비스 작업 구현에 주석을 추가하여 진정으로 멱등 원 작업만 재 시도하도록 aspect를 조정할 수 있습니다.&#x20;

```java
@Retention(RetentionPolicy.RUNTIME)
public @interface Idempotent {
    // marker annotation
}
```

aspect에 대한 멱등 원 작업만을 재 시도하는 것은 다음과 같이 `@Idempotent` 연산 만 일치하도록 pointcut 표현식을 수정하는 작업을 포함합니다.&#x20;

```markup
<aop:pointcut id="idempotentOperation"
        expression="execution(* com.xyz.myapp.service.*.*(..)) and
        @annotation(com.xyz.myapp.service.Idempotent)"/>
```
