1. 개요
Spring Retry는 실패한 작업을 자동으로 다시 호출하는 기능을 제공합니다. 이는 오류가 일시적일 수 있는 경우에 유용합니다(예: 일시적인 네트워크 결함).
이 예제에서는 Spring Retry 를 사용하는 다양한 방법( 어노테이션, RetryTemplate 및 콜백)을 볼 것입니다.
2. 메이븐 의존성
pom.xml 파일에 spring-retry 의존성을 추가하는 것으로 시작하겠습니다 .
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
<version>1.2.5.RELEASE</version>
</dependency>
또한 프로젝트에 Spring AOP를 추가해야 합니다.
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
<version>5.2.8.RELEASE</version>
</dependency>
최신 버전의 spring-retry 및 spring-aspect 의존성에 대해서는 Maven Central을 살펴보십시오 .
3. 스프링 재시도 활성화
애플리케이션에서 Spring Retry를 활성화하려면 @Configuration 클래스에 @EnableRetry 어노테이션 을 추가해야 합니다 .
@Configuration
@EnableRetry
public class AppConfig { ... }
4. 스프링 재시도 사용
4.1. @ 복구 없이 재시 도 가능
@Retryable 어노테이션을 사용하여 메소드에 재시도 기능을 추가 할 수 있습니다 .
@Service
public interface MyService {
@Retryable(value = RuntimeException.class)
void retryService(String sql);
}
여기에서 RuntimeException 이 발생 하면 재시도가 시도됩니다 .
당 @Retryable 의 기본 동작, 재시도 재시도 사이의 1 초 지연, 세 번까지 발생할 수 있습니다.
4.2. @Retryable 및 @Recover
이제 @Recover 어노테이션을 사용하여 복구 방법을 추가해 보겠습니다 .
@Service
public interface MyService {
@Retryable(value = SQLException.class)
void retryServiceWithRecovery(String sql) throws SQLException;
@Recover
void recover(SQLException e, String sql);
}
여기에서 SQLException 이 throw 되면 재시도가 시도됩니다 . @Recover의 때 애노테이션은 별도의 복구 방법을 정의 @Retryable 방법이 특정 예외 실패.
결과적으로 retryServiceWithRecovery 메서드가 세 번 시도한 후에도 SqlException 을 계속 throw 하면 recover() 메서드가 호출됩니다.
복구 핸들러에는 Throwable (선택 사항) 유형의 첫 번째 매개변수 와 동일한 반환 유형이 있어야 합니다. 다음 인수는 실패한 메소드의 인수 List에서 동일한 순서로 채워집니다.
4.3. @Retryable의 동작 사용자 정의
재시도 동작을 사용자 정의하기 위해 maxAttempts 및 backoff 매개변수를 사용할 수 있습니다 .
@Service
public interface MyService {
@Retryable( value = SQLException.class,
maxAttempts = 2, backoff = @Backoff(delay = 100))
void retryServiceWithCustomization(String sql) throws SQLException;
}
최대 2회의 시도와 100밀리초의 지연이 있습니다.
4.4. 스프링 속성 사용
@Retryable 어노테이션 에서 속성을 사용할 수도 있습니다 .
이를 시연하기 위해 delay 및 maxAttempts 값을 속성 파일로 외부화하는 방법을 살펴보겠습니다 .
먼저 retryConfig 라는 파일에 속성을 정의해 보겠습니다. 속성 :
retry.maxAttempts=2
retry.maxDelay=100
그런 다음 @Configuration 클래스에 이 파일을 로드 하도록 지시 합니다.
// ...
@PropertySource("classpath:retryConfig.properties")
public class AppConfig { ... }
마지막으로, 우리는의 값을 삽입 할 수 retry.maxAttempts 및 retry.maxDelay 우리의 @Retryable 정의를 :
@Service
public interface MyService {
@Retryable( value = SQLException.class, maxAttemptsExpression = "${retry.maxAttempts}",
backoff = @Backoff(delayExpression = "${retry.maxDelay}"))
void retryServiceWithExternalizedConfiguration(String sql) throws SQLException;
}
주의하시기 바랍니다 우리가 지금 사용하고있는 maxAttemptsExpression 및 delayExpression 대신 maxAttempts 및 지연 .
5. 템플릿 재시도
5.1. 재시도 작업
Spring Retry는 일련의 execute() 메서드를 제공하는 RetryOperations 인터페이스를 제공 합니다.
public interface RetryOperations {
<T> T execute(RetryCallback<T> retryCallback) throws Exception;
...
}
RetryCallback 의 파라미터이며, () 실행은 , 필요에 따라 실패 시도하는 것을 비즈니스 로직의 삽입을 허용하는 인터페이스이다 :
public interface RetryCallback<T> {
T doWithRetry(RetryContext context) throws Throwable;
}
5.2. 재시도 템플릿 구성
RetryTemplate는 의 구현입니다 RetryOperations .
@Configuration 클래스 에서 RetryTemplate 빈을 구성해 보겠습니다 .
@Configuration
public class AppConfig {
//...
@Bean
public RetryTemplate retryTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();
FixedBackOffPolicy fixedBackOffPolicy = new FixedBackOffPolicy();
fixedBackOffPolicy.setBackOffPeriod(2000l);
retryTemplate.setBackOffPolicy(fixedBackOffPolicy);
SimpleRetryPolicy retryPolicy = new SimpleRetryPolicy();
retryPolicy.setMaxAttempts(2);
retryTemplate.setRetryPolicy(retryPolicy);
return retryTemplate;
}
}
RetryPolicy는 동작이 재 시도되어야 할 때를 결정한다.
SimpleRetryPolicy가 일정 회수를 시도하는데 사용된다. 반면에 BackOffPolicy 는 재시도 사이의 백오프를 제어하는 데 사용됩니다.
마지막으로 FixedBackOffPolicy 는 계속하기 전에 고정된 기간 동안 일시 중지됩니다.
5.3. RetryTemplate 사용
재시도 처리로 코드를 실행하려면 r etryTemplate.execute() 메서드를 호출할 수 있습니다 .
retryTemplate.execute(new RetryCallback<Void, RuntimeException>() {
@Override
public Void doWithRetry(RetryContext arg0) {
myService.templateRetryService();
...
}
});
익명 클래스 대신 람다 식을 사용할 수 있습니다.
retryTemplate.execute(arg0 -> {
myService.templateRetryService();
return null;
});
6. 청취자
리스너는 재시도 시 추가 콜백을 제공합니다. 그리고 이를 다양한 재시도에 걸쳐 다양한 교차 문제에 사용할 수 있습니다.
6.1. 콜백 추가
콜백은 RetryListener 인터페이스 에서 제공됩니다 .
public class DefaultListenerSupport extends RetryListenerSupport {
@Override
public <T, E extends Throwable> void close(RetryContext context,
RetryCallback<T, E> callback, Throwable throwable) {
logger.info("onClose);
...
super.close(context, callback, throwable);
}
@Override
public <T, E extends Throwable> void onError(RetryContext context,
RetryCallback<T, E> callback, Throwable throwable) {
logger.info("onError");
...
super.onError(context, callback, throwable);
}
@Override
public <T, E extends Throwable> boolean open(RetryContext context,
RetryCallback<T, E> callback) {
logger.info("onOpen);
...
return super.open(context, callback);
}
}
개방 과 가까운 동안 콜백은, 전에 전체 재시도 후 온 의 OnError가 개인에게 적용 RetryCallback의 호출.
6.2. 리스너 등록
다음으로 RetryTemplate 빈에 리스너( DefaultListenerSupport) 를 등록합니다 .
@Configuration
public class AppConfig {
...
@Bean
public RetryTemplate retryTemplate() {
RetryTemplate retryTemplate = new RetryTemplate();
...
retryTemplate.registerListener(new DefaultListenerSupport());
return retryTemplate;
}
}
7. 결과 테스트
예제를 마치기 위해 결과를 확인하겠습니다.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(
classes = AppConfig.class,
loader = AnnotationConfigContextLoader.class)
public class SpringRetryIntegrationTest {
@Autowired
private MyService myService;
@Autowired
private RetryTemplate retryTemplate;
@Test(expected = RuntimeException.class)
public void givenTemplateRetryService_whenCallWithException_thenRetry() {
retryTemplate.execute(arg0 -> {
myService.templateRetryService();
return null;
});
}
}
테스트 로그에서 볼 수 있듯이 RetryTemplate 및 RetryListener를 적절하게 구성했습니다 .
2020-01-09 20:04:10 [main] INFO o.b.s.DefaultListenerSupport - onOpen
2020-01-09 20:04:10 [main] INFO o.baeldung.springretry.MyServiceImpl
- throw RuntimeException in method templateRetryService()
2020-01-09 20:04:10 [main] INFO o.b.s.DefaultListenerSupport - onError
2020-01-09 20:04:12 [main] INFO o.baeldung.springretry.MyServiceImpl
- throw RuntimeException in method templateRetryService()
2020-01-09 20:04:12 [main] INFO o.b.s.DefaultListenerSupport - onError
2020-01-09 20:04:12 [main] INFO o.b.s.DefaultListenerSupport - onClose
8. 결론
이 기사에서는 어노테이션, RetryTemplate 및 콜백 리스너 를 사용하여 Spring Retry를 사용하는 방법을 보았습니다 .