5.4.7 AOP 예제 by ks

이제 어떻게 모든 부분이 동작하는지를 보여준다. 우리는 그들을 모아 유용한 것을 할 수 있다.

비즈니스 서비스의 실행은 동시성 이슈 때문에 때때로 실패할 수 있다.(예를 들어서, 데드락 손실). 만약 동작이 재시도 되면, 다음 시도에 성공할 가능성이 있다. 그런 컨디션(충돌 해결을 위해 사용자에게 돌아갈 필요가없는 멱등 원 (idempotent) 작업)에서 재시도하기 위해 적절한 비즈니스 서비스를 위해, 우리는 투명하게 작업을 재 시도하여 클라이언트가 PessimisticLockingFailureException을 보지 못하도록한다. 그는 서비스 계층의 여러 서비스를 명확하게 차단하므로 요구 사항을 충족시켜야 한다.

멱등성 : 멱등법칙(冪等法則) 또는 멱등성(冪等性, 영어: idempotent)은 수학이나 전산학에서 연산의 한 성질을 나타내는 것으로, 연산을 여러 번 적용하더라도 결과가 달라지지 않는 성질을 의미한다

실행 재시도하기를 원하기 때문에, around advice를 사용할 필요가 있고, 여러번 proceed를 부를 수 있다. 아래 리스팅은 기본 aspect 확장체다.

@Aspect
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;
    }

    @Around("com.xyz.myapp.SystemArchitecture.businessService()")
    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 인터페이스를 확장해서 트랜잭션 advice(매번 재시도하는 신선한 트랜잭션을 원하는) 보다 더 높은 aspect의 우선순위를 세팅할 수 있다. maxRetries와 order 프로퍼티는 둘다 스프링에 의해 설정된다(configured). 메인 액션은 doConcurrentOperation arcount advice에서 발생한다. 그 순간에 각 businessService()에 재시도 로직을 적용한다. 우리는 진행을 시도하고, PessimisticLockingFailureException으로 실패 할 경우 다시 시도하지 않은 한 다시 시도한다.

아래는 스프링 configuration이다.

<aop:aspectj-autoproxy/>

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

멱등 원 작업 만 재 시도하도록 애스펙트를 수정하려면 다음과 같은 멱등 원 주석을 정의 할 수 있다.

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

그리고나서 어노테이션을 서비스 동작의 확장체를 어노테이트하기 위해 사용할 수 있다. 멱등 원들만 연산을 재 시도하기 위해 aspect에 대한 변경은 다음과 같이 @Idempotent 연산 만 일치하도록 pointcut 표현식을 수정하는 것을 포함한다.

@Around("com.xyz.myapp.SystemArchitecture.businessService() && " +
        "@annotation(com.xyz.myapp.service.Idempotent)")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
    ...
}

Last updated