AOP 示例
既然您已经了解了所有构成部分的工作原理,我们可以将它们组合起来做一些有用的事情。
业务服务的执行有时会因为并发问题(例如,死锁失败者)而失败。如果操作被重试,它很可能在下一次尝试中成功。对于在这种条件下适合重试的业务服务(不需要返回给用户进行冲突解决的幂等操作),我们希望透明地重试操作,以避免客户端看到 PessimisticLockingFailureException
。这是一个明显贯穿服务层中多个服务的需求,因此,非常适合通过切面实现。
因为我们想要重试操作,所以我们需要使用环绕通知,以便我们可以多次调用 proceed
。以下清单显示了基本的切面实现:
@Around("com.xyz.CommonPointcuts.businessService()")
引用了 共享命名切点定义 中定义的 businessService
命名切点。
请注意,切面实现了 Ordered
接口,以便我们可以将切面的优先级设置高于事务通知(我们希望每次重试都有一个新的事务)。maxRetries
和 order
属性都由 Spring 配置。主要操作发生在 doConcurrentOperation
环绕通知中。请注意,目前,我们将重试逻辑应用于每个 businessService
。我们尝试继续执行,如果因 PessimisticLockingFailureException
失败,我们会再次尝试,除非我们已用尽所有重试尝试。
相应的 Spring 配置如下:
为了优化切面,使其仅重试幂等操作,我们可以定义以下 Idempotent
注解:
然后,我们可以使用该注解来注解服务操作的实现。对切面进行更改以仅重试幂等操作涉及优化切点表达式,以便只有 @Idempotent
操作匹配,如下所示: