由于并发问题(例如,死锁失败者),业务服务的执行有时会失败。如果该操作被重试,则很可能在下一次尝试时成功。对于在这种情况下适合重试的业务服务(不需要返回给用户解决冲突的幂等操作),我们希望透明地重试操作以避免客户端看到 PessimisticLockingFailureException
. 这是一个明确跨越服务层中多个服务的要求,因此非常适合通过切面实现。
复制 @ 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.CommonPointcuts.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;
}
}
复制 < 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
}
复制 @ Around ( "com.xyz.myapp.CommonPointcuts.businessService() && " +
"@annotation(com.xyz.myapp.service.Idempotent)" )
public Object doConcurrentOperation( ProceedingJoinPoint pjp) throws Throwable {
// ...
}