An AOP Example

Dev.Hammy·2024년 3월 6일
0

이제 모든 구성 요소가 어떻게 작동하는지 살펴보았으므로 이를 함께 모아 유용한 작업을 수행할 수 있습니다.

동시성 문제(예: 교착 상태 패자)로 인해 비즈니스 서비스 실행이 실패하는 경우가 있습니다. 작업을 다시 시도하면 다음 시도에서 성공할 가능성이 높습니다. 이러한 조건(충돌 해결을 위해 사용자에게 돌아갈 필요가 없는 멱등성 작업)에서 재시도하는 것이 적절한 비즈니스 서비스의 경우 클라이언트가 PessimisticLockingFailureException을 보지 않도록 작업을 투명하게 재시도하려고 합니다. 이는 서비스 계층의 여러 서비스를 명확하게 구분하는 요구 사항이므로 aspect을 통해 구현하는 데 이상적입니다.

작업을 다시 시도하고 싶기 때문에 진행을 여러 번 호출할 수 있도록 around 어드바이스를 사용해야 합니다. 다음 목록은 기본 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.CommonPointcuts.businessService()") // (1)
	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;
	}
}

(1) 명명된 Pointcut 정의 공유에 정의된 pointcut이라는 이름의 businessService를 참조합니다.

애스펙트는 Ordered 인터페이스를 구현하므로 트랜잭션 aspect보다 애스펙트의 우선순위를 더 높게 설정할 수 있습니다(재시도할 때마다 새로운 트랜잭션을 원함). maxRetriesorder 속성(properties)은 모두 Spring에 의해 구성됩니다. 주요 작업은 aspect과 관련된 doConcurrentOperation에서 발생합니다. 지금은 각 businessService에 재시도 논리를 적용합니다. 계속 진행하려고 시도하고 PessimisticLockingFailureException으로 실패하면 재시도 횟수를 모두 소진하지 않는 한 다시 시도합니다.

해당 Spring 구성은 다음과 같습니다.

<aop:aspectj-autoproxy/>

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

멱등성 작업만 재시도하도록 측면을 개선하기 위해 다음과 같은 Idempotent annotation을 정의할 수 있습니다.

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

그런 다음 annotation을 사용하여 서비스 작업 구현에 annotation을 달 수 있습니다. 멱등성 연산만 재시도하는 aspect 변경에는 다음과 같이 @Idempotent 연산만 일치하도록 포인트컷 표현식을 정제하는 작업이 포함됩니다.

@Around("execution(* com.xyz..service.*.*(..)) && " +
		"@annotation(com.xyz.service.Idempotent)")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
	// ...
}

0개의 댓글