在使用Spring/Java和面向方面编程编写代码时,我面临着一个问题。在服务类中,我有使用@retryable的重试方法和使用@recovery的恢复方法。
这两个方法中的每一个都附加到方面。TestProcessService中的可重试方法“TriggerJob”附加到TestAspect类中的这些方法--BeforeTestTriggerJobsAdvision、AfterTestTriggerJobsAdvision、OnErrorTestTriggerJobsAdvision。它们都工作得很好,并在正确的时间被触发。
问题陈述:TestProcessService中的恢复方法“Recovery”附加到TestAspect类中的这些方法--beforeRecoveryTestJobsAdvision、OnerrorRecoveryTestTriggerJobsAdvision和AfterRecoveryTestTriggerJobsAdvision。
但是,一旦代码到达TestProcessService中的恢复方法,就不会调用这些方面方法。
代码如下:
@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);
}
}
@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();
}
}
@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");
}
}
日志输出:
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
我不是Spring用户,但对所有AOP都感兴趣,包括AspectJ和Spring AOP。我喜欢你的小拼图。多亏了你的MCVE,我才能够重现这个问题并调试到它里面。这是一个完美的例子,说明为什么MCVE比简单地发布一堆代码片段要优越得多。所以谢谢你,请保持这种提问方式。
当查看调试器中的情况时,您会看到,当方面进入TriggerJob
时,我们在方法AnnotationAwareRetryOperationsInterceptor.invoke
中有以下代码:
@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选择构造委托,稍后将用于调用recovere
。它是用目标对象invocation.getthis()
构造的,它指向原始对象,即test_bdaProcessService
实例。此时,代码可以简单地使用invocation.getproxy()
,这将指向AOP代理,即test_bdaProcessService$$EnhancerbySpringCglib$$2f8076ac
实例。问题是,目标对象引用被传递到调用recovery
的地方,此时对应的恢复程序实例只知道目标对象,不再知道对应的代理对象。
当我将代理作为目标分配给委托时,调用了您的advision方法。
所以我们在这里讨论的是一个Spring限制。我不知道这是为了避免任何其他相关问题而深思熟虑的选择,还是只是一个疏忽。
更新:我代表您创建了Spring重试问题#244。你想订阅它,这样你就可以知道它是否/何时将被修复。
更新2:这个问题已经被修复,被合并到主分支中,并且可能会成为即将发布的1.3.2版本的一部分。现在,您只需克隆Spring重试,自己构建并使用快照。我对您的MCVE进行了重新测试,现在恢复方法的方面就像预期的那样开始了。
问题很简单 在这里打破头! 编辑:一个小突破。我打印了目标,它返回的是SimpleJPrepository,而不是实际的存储库。
我正在使用Spring AOP实现自定义注释处理。我有下面的代码。 //应用程序配置 出于测试目的,我创建了下面的bean 无论何时启动应用程序,它都将调用TestCacheDemo类的test方法,并将定时器设置为在3秒后触发,这样我就可以从timer任务的run方法内部调用带注释的方法getCacheValue。但是当调用带注释的方法时,不会调用注释处理器。因此,我无法进行注释处理。请让我知道
对于上面的modbus轮询查询,我没有得到哪个是crc值,以及使用了什么类型的crc。它是怎么来的,77是设备的id。请指引我。 我从轮询设备得到以下响应
我已在centos 7上更新了我的应用程序服务器。使用PHP7.3实现x。当我运行控制台命令时,会出现如下错误 下面是堆栈日志。 我不明白该往哪里看,可能是什么问题。请引导任何人。
我正在测试一个Spring重试,但似乎没有调用恢复。试图让它工作,但似乎详尽无遗。我传递给@recover no argument,Throwable,exception。改变了重试依赖的版本,似乎它包含在spring boot的aop中,并删除了它。Creading Geting Recovery没有被调用,出现以下异常Messege。 请求处理失败;嵌套异常是org.springframewo
我想训练一个模特。我有将近150个类,我正在使用ImageDataGenerator来扩展我的数据集。我还使用模型检查点和csvlogger来保存权重。当我开始训练时,它在第一个纪元的某个时刻给了我一个错误。如果有帮助的话,我使用的图像是灰度图像。 这是我的代码: 这是我的回拨: 拟合模型: 我收到的错误是这样的: 纪元 1/10 3428/4128 [======================