首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >@Recover方法未被Spring通知截获

@Recover方法未被Spring通知截获
EN

Stack Overflow用户
提问于 2021-06-02 17:59:42
回答 1查看 590关注 0票数 1

在使用Spring/Java和面向方面的编程编写代码时,我面临一个问题。在服务类中,我有使用@Retryable的retry方法和使用@Recover的恢复方法。

这两种方法中的每一种都附加到各个方面。在triggerJob类中,TestProcessService中的Retryable“afterTestTriggerJobsAdvice”附加到这些方法中- beforeTestTriggerJobsAdvice、afterTestTriggerJobsAdvice、onErrorTestTriggerJobsAdvice。他们都工作得很好,并在正确的时间被触发。

问题陈述:-- TestProcessService中的恢复方法--在TestAspect类中附加到这些方法- beforeRecoveryTestJobsAdvice、onErrorRecoveryTestTriggerJobsAdvice和afterRecoveryTestTriggerJobsAdvice中。

但是,一旦代码到达内部的恢复方法,所有这些方面方法都不会被调用。

以下是代码:

调度程序类(触发TEST_MyProcessService类内的方法)

代码语言:javascript
复制
@Slf4j
@Component
public class TEST_ScheduledProcessPoller {

    private final TEST_MyProcessService MyProcessService;
    private final MyServicesConfiguration MyServicesConfiguration;

    public TEST_ScheduledProcessPoller(TEST_MyProcessService MyProcessService,
                                  MyServicesConfiguration MyServicesConfiguration) {
        this.MyProcessService = MyProcessService;
        this.MyServicesConfiguration = MyServicesConfiguration;
    }

    @Scheduled(cron = "0 0/2 * * * *")
    public void scheduleTaskWithFixedDelay() {
        try {
            log.info("scheduleTaskWithFixedDelay");
            this.triggerMyJobs(true);
        } catch (Exception e) {
            log.error(e.getMessage());
        }
    }

    protected void triggerMyJobs(boolean isDaily) throws Exception {
        log.info("triggerMyJobs");
        MyServiceType serviceType = this.MyServicesConfiguration.getMy();
        this.MyProcessService.triggerJob(serviceType, isDaily, 1L);
    }
}

服务类:

代码语言:javascript
复制
@Slf4j
@Service
public class TEST_MyProcessService {

    @Retryable(maxAttemptsExpression = "${api.retry.limit}", backoff = @Backoff(delayExpression = "${api.retry.max-interval}"))
    public void triggerJob(MyServiceType MyServiceType, boolean isDaily, long eventId) {
        // Some code here that can throw exceptions.
        log.info("triggerJob");
        throw new RuntimeException("triggerJob");
    }

    @Recover
    public void recover(MyServiceType MyServiceType, boolean isDaily, long eventId) {
        log.info("recover");
        // Some code here that can throw exceptions.
        throw new RuntimeException();
    }
}

方面类:

代码语言:javascript
复制
@Component
@Slf4j
public class TEST_MyAspect {

    @Pointcut("execution(* packgName.otherProj.services.TEST_MyProcessService.triggerJob(..))")
    public void MyTriggerJobs() {
    }

    @Pointcut("execution(* packgName.otherProj.services.TEST_MyProcessService.recover(..))")
    public void MyRecoverJobs() {
    }

    @Before("MyTriggerJobs()")
    public void beforeMyTriggerJobsAdvice(JoinPoint joinPoint) {
        log.info("log beforeMyTriggerJobsAdvice");
    }

    @AfterReturning("MyTriggerJobs()")
    public void afterMyTriggerJobsAdvice(JoinPoint joinPoint) {
        log.info("log afterMyTriggerJobsAdvice");
    }

    @AfterThrowing(value = "MyTriggerJobs()", throwing = "error")
    public void onErrorMyTriggerJobsAdvice(JoinPoint joinPoint, Throwable error) {
        log.info("log onErrorMyTriggerJobsAdvice");
    }

    @Before("MyRecoverJobs()")
    public void beforeMyRecoverJobsAdvice(JoinPoint joinPoint) {
        log.info("log beforeMyRecoverJobsAdvice");
    }

    @AfterThrowing(value = "MyRecoverJobs()", throwing = "error")
    public void onErrorRecoveryMyTriggerJobsAdvice(JoinPoint joinPoint, Throwable error) {
        log.info("log onErrorRecoveryMyTriggerJobsAdvice");
    }


    @AfterReturning("MyRecoverJobs()")
    public void afterRecoveryMyTriggerJobsAdvice(JoinPoint joinPoint) {
        log.info("log afterRecoveryMyTriggerJobsAdvice");
    }
}

日志输出:

代码语言:javascript
复制
2021-06-02 20:56:00.016  INFO [,60b7f0602b2ecb0deefc04d6840b6274,eefc04d6840b6274,true] 92605 --- [   scheduling-1] c.c.p.r.c.TEST_ScheduledProcessPoller    : scheduleTaskWithFixedDelay
2021-06-02 20:56:00.016  INFO [,60b7f0602b2ecb0deefc04d6840b6274,eefc04d6840b6274,true] 92605 --- [   scheduling-1] c.c.p.r.c.TEST_ScheduledProcessPoller    : triggerBdaJobs
2021-06-02 20:56:00.051  INFO [,60b7f0602b2ecb0deefc04d6840b6274,eefc04d6840b6274,true] 92605 --- [   scheduling-1] c.c.p.r.component.aspect.TEST_BdaAspect  : log beforeBdaTriggerJobsAdvice
2021-06-02 20:56:00.060  INFO [,60b7f0602b2ecb0deefc04d6840b6274,eefc04d6840b6274,true] 92605 --- [   scheduling-1] c.c.p.r.services.TEST_BdaProcessService  : triggerJob
2021-06-02 20:56:00.061  INFO [,60b7f0602b2ecb0deefc04d6840b6274,eefc04d6840b6274,true] 92605 --- [   scheduling-1] c.c.p.r.component.aspect.TEST_BdaAspect  : log onErrorBdaTriggerJobsAdvice
2021-06-02 20:56:05.065  INFO [,60b7f0602b2ecb0deefc04d6840b6274,eefc04d6840b6274,true] 92605 --- [   scheduling-1] c.c.p.r.component.aspect.TEST_BdaAspect  : log beforeBdaTriggerJobsAdvice
2021-06-02 20:56:05.066  INFO [,60b7f0602b2ecb0deefc04d6840b6274,eefc04d6840b6274,true] 92605 --- [   scheduling-1] c.c.p.r.services.TEST_BdaProcessService  : triggerJob
2021-06-02 20:56:05.066  INFO [,60b7f0602b2ecb0deefc04d6840b6274,eefc04d6840b6274,true] 92605 --- [   scheduling-1] c.c.p.r.component.aspect.TEST_BdaAspect  : log onErrorBdaTriggerJobsAdvice
2021-06-02 20:56:10.070  INFO [,60b7f0602b2ecb0deefc04d6840b6274,eefc04d6840b6274,true] 92605 --- [   scheduling-1] c.c.p.r.component.aspect.TEST_BdaAspect  : log beforeBdaTriggerJobsAdvice
2021-06-02 20:56:10.070  INFO [,60b7f0602b2ecb0deefc04d6840b6274,eefc04d6840b6274,true] 92605 --- [   scheduling-1] c.c.p.r.services.TEST_BdaProcessService  : triggerJob
2021-06-02 20:56:10.070  INFO [,60b7f0602b2ecb0deefc04d6840b6274,eefc04d6840b6274,true] 92605 --- [   scheduling-1] c.c.p.r.component.aspect.TEST_BdaAspect  : log onErrorBdaTriggerJobsAdvice
2021-06-02 20:56:10.070  INFO [,60b7f0602b2ecb0deefc04d6840b6274,eefc04d6840b6274,true] 92605 --- [   scheduling-1] c.c.p.r.services.TEST_BdaProcessService  : recover
2021-06-02 20:56:10.070 ERROR [,60b7f0602b2ecb0deefc04d6840b6274,eefc04d6840b6274,true] 92605 --- [   scheduling-1] c.c.p.r.c.TEST_ScheduledProcessPoller    : null
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-06-04 05:28:39

我不是Spring用户,但对AOP的所有内容都感兴趣,包括AspectJ和Spring。我喜欢你的小谜题。多亏了您的https://stackoverflow.com/help/mcve,我才得以重现问题并调试到其中。这是一个完美的例子,说明为什么MCVE比简单地发布一堆代码片段要好得多。因此,谢谢你,请继续用这种方式提问。

当查看调试器中的情况时,您会看到,当方面继续进入triggerJob时,在某个时候我们使用的是AnnotationAwareRetryOperationsInterceptor.invoke方法,在这里我们有以下代码:

代码语言:javascript
复制
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
    MethodInterceptor delegate = getDelegate(invocation.getThis(), invocation.getMethod());
    if (delegate != null) {
        return delegate.invoke(invocation);
    }
    else {
        return invocation.proceed();
    }
}

此时,Spring做出了构造委托的选择,该委托稍后将用于调用recover。它是用目标对象invocation.getThis()构造的,它指向原始对象,即TEST_BdaProcessService实例。此时,代码可以直接使用invocation.getProxy(),这将指向AOP代理,即TEST_BdaProcessService$$EnhancerBySpringCGLIB$$2f8076ac实例。问题是,目标对象引用被传递到调用recover的点,而此时对应的恢复性实例只知道目标对象,不再知道相应的代理对象。

当我实验将代理分配给委托作为目标时,您的通知方法就会被调用。

所以我们在这里讨论的是一个弹簧限制。我不知道这是一个故意的选择,是为了避免任何其他相关的问题,还是仅仅是一个疏忽。

更新:我代表您创建了春季重试问题#244。你想订阅它,这样你就可以知道它是否会/什么时候被修复。

更新2:问题已经解决,合并到主分支中,并且可能会成为即将发布的1.3.2版本的一部分。现在,您只需复制Spring重试,自行构建并使用快照即可。我重新测试了你的MCVE,这方面现在开始如预期的恢复方法。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67810277

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档