此版本仍在开发中,尚未被视为稳定版本。对于最新的稳定版本,请使用 Spring Framework 6.2.0! |
AOP 示例
现在您已经了解了所有组成部分的工作原理,我们可以将它们放在一起进行 一些有用的东西。
业务服务的执行有时会由于并发问题(对于
例如,一个死锁失败者)。如果重试作,则可能会成功
下次尝试时。对于适合在此类
条件(无需因冲突而返回给用户的幂等作
resolution)中,我们希望透明地重试该作,以避免客户端看到PessimisticLockingFailureException
.这是一个明确贯穿的要求
服务层中的多个服务,因此非常适合通过
方面。
因为我们想要重试作,所以我们需要使用 around advice,以便我们可以
叫proceed
多次。下面的清单显示了基本的 aspect 实现:
-
Java
-
Kotlin
@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()")
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
class ConcurrentOperationExecutor : Ordered {
companion object {
private const val DEFAULT_MAX_RETRIES = 2
}
var maxRetries = DEFAULT_MAX_RETRIES
private var order = 1
override fun getOrder(): Int {
return this.order
}
fun setOrder(order: Int) {
this.order = order
}
@Around("com.xyz.CommonPointcuts.businessService()")
fun doConcurrentOperation(pjp: ProceedingJoinPoint): Any {
var numAttempts = 0
var lockFailureException: PessimisticLockingFailureException?
do {
numAttempts++
try {
return pjp.proceed()
} catch (ex: PessimisticLockingFailureException) {
lockFailureException = ex
}
} while (numAttempts <= this.maxRetries)
throw lockFailureException!!
}
@Around("com.xyz.CommonPointcuts.businessService()")
引用businessService
在共享命名切入点定义中定义的命名切入点。
请注意,该 aspect 实现了Ordered
接口,以便我们可以设置
方面高于 Transaction Advice(我们希望每次
retry)。这maxRetries
和order
properties 都是由 Spring 配置的。这
main作发生在doConcurrentOperation
周围建议。请注意,对于
矩,我们将重试逻辑应用于每个businessService
.我们努力进行,
如果我们失败了PessimisticLockingFailureException
,我们会重试,除非
我们已经用尽了所有的重试尝试。
相应的 Spring 配置如下:
-
Java
-
Kotlin
-
Xml
@Configuration
@EnableAspectJAutoProxy
public class ApplicationConfiguration {
@Bean
public ConcurrentOperationExecutor concurrentOperationExecutor() {
ConcurrentOperationExecutor executor = new ConcurrentOperationExecutor();
executor.setMaxRetries(3);
executor.setOrder(100);
return executor;
}
}
@Configuration
@EnableAspectJAutoProxy
class ApplicationConfiguration {
@Bean
fun concurrentOperationExecutor() = ConcurrentOperationExecutor().apply {
maxRetries = 3
order = 100
}
}
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<aop:aspectj-autoproxy />
<bean id="concurrentOperationExecutor"
class="com.xyz.service.impl.ConcurrentOperationExecutor">
<property name="maxRetries" value="3"/>
<property name="order" value="100"/>
</bean>
</beans>
为了优化 aspect 以便它仅重试幂等作,我们可以定义以下内容Idempotent
注解:
-
Java
-
Kotlin
@Retention(RetentionPolicy.RUNTIME)
// marker annotation
public @interface Idempotent {
}
@Retention(AnnotationRetention.RUNTIME)
// marker annotation
annotation class Idempotent
然后,我们可以使用 annotation 来注释服务作的实现。变化
到仅重试幂等作涉及优化切入点
表达式,以便仅@Idempotent
作匹配,如下所示:
-
Java
-
Kotlin
@Around("execution(* com.xyz..service.*.*(..)) && " +
"@annotation(com.xyz.service.Idempotent)")
public Object doConcurrentOperation(ProceedingJoinPoint pjp) throws Throwable {
// ...
return pjp.proceed(pjp.getArgs());
}
@Around("execution(* com.xyz..service.*.*(..)) && " +
"@annotation(com.xyz.service.Idempotent)")
fun doConcurrentOperation(pjp: ProceedingJoinPoint): Any? {
// ...
return pjp.proceed(pjp.args)
}