У меня есть прототип bean-компонента, реализующий Runnable, который должен повторить свой run-метод и что-то сделать, если достигнуто максимальное количество повторов. Теперь у меня проблема в том, что метод восстановления, кажется, всегда вызывается из одного и того же компонента Spring, а не из соответствующего экземпляра.
Это мой код на данный момент:
RetryableRunnable
@Slf4j
@AllArgsConstructor
public class RetryableRunnable implements Runnable {
private final RetryDemoService retryDemoService;
private final Status someStatus;
@Override
@Retryable(
value = { RuntimeException.class },
maxAttempts = 2,
backoff = @Backoff(delay = 2000))
public void run() {
log.info( "+++ RetryableRunnable executed! +++" );
retryDemoService.demoRun();
}
@Recover
private void recover() {
retryDemoService.demoRecover();
log.info( String.valueOf( someStatus ) );
}
}
Конфигурация
@Configuration
@AllArgsConstructor
@EnableRetry(proxyTargetClass = true)
public class RetryDemoConfig {
private final RetryDemoService retryDemoService;
@Bean
@Scope( "prototype" )
public RetryableRunnable retryableRunnable(Status status) {
return new RetryableRunnable( retryDemoService, status );
}
}
Сервис
@Service
@Slf4j
public class RetryDemoService {
void demoRun() {
log.info( "+++ Run! +++" );
}
void demoRecover() {
log.info( "+++ Recover! +++" );
}
}
Статусное перечисление
public enum Status {
STATUS1, STATUS2
}
Протестируйте, чтобы выявить проблему
@RunWith( SpringRunner.class )
@SpringBootTest
public class RetryableRunnableTest {
@Autowired
private BeanFactory beanFactory;
@MockBean
RetryDemoService retryDemoService;
@Test
public void retrieableRunnableIsRetriedOnlyThreeTimesAndRecoverMethodIsRun() throws InterruptedException {
RetryableRunnable testInstance1 = beanFactory.getBean( RetryableRunnable.class, Status.STATUS1 );
RetryableRunnable testInstance2 = beanFactory.getBean( RetryableRunnable.class, Status.STATUS2 );
doThrow( new RuntimeException() )
.doThrow( new RuntimeException() )
.doThrow( new RuntimeException() )
.when( retryDemoService ).demoRun();
Thread thread1 = new Thread( testInstance1 );
thread1.start();
thread1.join();
Thread thread2 = new Thread( testInstance2 );
thread2.start();
thread2.join();
}
}
Теперь вывод журнала:
+++ RetryableRunnable executed! +++
+++ RetryableRunnable executed! +++
STATUS1
+++ RetryableRunnable executed! +++
+++ RetryableRunnable executed! +++
STATUS1
Пока должно быть:
+++ RetryableRunnable executed! +++
+++ RetryableRunnable executed! +++
STATUS1
+++ RetryableRunnable executed! +++
+++ RetryableRunnable executed! +++
STATUS2
Когда я отлаживаю этот тестовый метод, RetryRunnable @ 3053 вызывает метод восстановления в первый и второй раз!
Это ошибка или мне не хватает понимания концепции? Что я могу сделать, чтобы решить эту проблему и вызвать соответствующее поле «Статус» прототипного компонента?