Panduan untuk Spring Retry

1. Ikhtisar

Spring Retry memberikan kemampuan untuk secara otomatis menjalankan kembali operasi yang gagal. Ini berguna jika kesalahan mungkin bersifat sementara (seperti kesalahan jaringan sesaat).

Dalam tutorial ini, kita akan melihat berbagai cara menggunakan Spring Retry: anotasi, RetryTemplate , dan callback.

2. Ketergantungan Maven

Mari kita mulai dengan menambahkan dependensi spring-retry ke dalam file pom.xml kita :

 org.springframework.retry spring-retry 1.2.5.RELEASE 

Kami juga perlu menambahkan Spring AOP ke dalam proyek kami:

 org.springframework spring-aspects 5.2.8.RELEASE 

Kunjungi Maven Central untuk versi terbaru dependensi spring-retry dan spring-aspect.

3. Mengaktifkan Spring Retry

Untuk mengaktifkan Spring Retry di aplikasi, kita perlu menambahkan anotasi @EnableRetry ke kelas @Configuration kita :

@Configuration @EnableRetry public class AppConfig { ... }

4. Menggunakan Spring Retry

4.1. @ Dapat Dikembalikan Tanpa Pemulihan

Untuk menambahkan fungsionalitas coba lagi ke metode, kita dapat menggunakan anotasi @Retrizable :

@Service public interface MyService { @Retryable(value = RuntimeException.class) void retryService(String sql); }

Dalam contoh ini, percobaan ulang akan dilakukan saat RuntimeException dilemparkan .

Sesuai dengan perilaku default @Retryable , percobaan ulang dapat terjadi hingga tiga kali, dengan penundaan satu detik di antara percobaan ulang .

4.2. @Retryable dan @Recover

Sekarang mari tambahkan metode pemulihan menggunakan anotasi @Recover :

@Service public interface MyService { @Retryable(value = SQLException.class) void retryServiceWithRecovery(String sql) throws SQLException; @Recover void recover(SQLException e, String sql); }

Dalam contoh ini, percobaan ulang akan dilakukan ketika SQLException dilemparkan . The @Recover penjelasan mendefinisikan sebuah metode pemulihan yang terpisah ketika @Retryable metode gagal dengan pengecualian tertentu.

Akibatnya, jika metode retryServiceWithRecovery terus menampilkan SqlException setelah 3 upaya, metode recover () akan dipanggil.

Penangan pemulihan harus memiliki parameter pertama dari tipe Throwable (opsional) dan tipe pengembalian yang sama.Argumen berikut diisi dari daftar argumen metode gagal dalam urutan yang sama.

4.3. Menyesuaikan Perilaku @ Retrizable

Untuk menyesuaikan perilaku percobaan ulang, kita dapat menggunakan parameter maxAttempts dan backoff :

@Service public interface MyService { @Retryable( value = SQLException.class, maxAttempts = 2, backoff = @Backoff(delay = 100)) void retryServiceWithCustomization(String sql) throws SQLException; }

Dalam contoh di atas, akan ada hingga 2 upaya dan penundaan 100 milidetik.

4.4. Menggunakan Spring Properties

Kita juga bisa menggunakan properti di anotasi @Retrizable .

Untuk mendemonstrasikan ini, kita akan melihat bagaimana mengeksternalisasi nilai delay dan maxAttempts ke dalam file properti .

Pertama, mari kita definisikan properti dalam file bernama retryConfig. properti :

retry.maxAttempts=2 retry.maxDelay=100

Kami kemudian menginstruksikan kelas @Configuration kami untuk memuat file ini:

// ... @PropertySource("classpath:retryConfig.properties") public class AppConfig { ... }

Terakhir, kami dapat memasukkan nilai retry.maxAttempts dan retry.maxDelay dalam definisi @Retrizable :

@Service public interface MyService { @Retryable( value = SQLException.class, maxAttemptsExpression = "${retry.maxAttempts}", backoff = @Backoff(delayExpression = "${retry.maxDelay}")) void retryServiceWithExternalizedConfiguration(String sql) throws SQLException; }

Harap perhatikan bahwa kami sekarang menggunakan maxAttemptsExpression dan delayExpression, bukan maxAttempts dan delay .

5. RetryTemplate

5.1 RetryOperations

Spring Retry menyediakan antarmuka RetryOperations yang menyediakan sekumpulan metode execute () :

public interface RetryOperations {  T execute(RetryCallback retryCallback) throws Exception; ... }

The RetryCallback yang merupakan parameter dari execute () adalah sebuah antarmuka yang memungkinkan penyisipan logika bisnis bahwa kebutuhan untuk dicoba pada kegagalan:

public interface RetryCallback { T doWithRetry(RetryContext context) throws Throwable; }

5.2. Konfigurasi RetryTemplate

The RetryTemplate merupakan implementasi dari RetryOperations . Mari kita konfigurasikan kacang RetryTemplate di kelas @Configuration kita :

@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; } } 

The RetryPolicy menentukan kapan operasi harus dicoba.

Sebuah SimpleRetryPolicy digunakan untuk mencoba kembali sejumlah tetap kali. Di sisi lain, BackOffPolicy digunakan untuk mengontrol backoff antara percobaan ulang.

Terakhir, FixedBackOffPolicy dijeda selama jangka waktu tertentu sebelum melanjutkan.

5.3. Menggunakan RetryTemplate

Untuk menjalankan kode dengan penanganan coba lagi kita bisa memanggil metode r etryTemplate.execute () :

retryTemplate.execute(new RetryCallback() { @Override public Void doWithRetry(RetryContext arg0) { myService.templateRetryService(); ... } });

Alih-alih kelas anonim, kita bisa menggunakan ekspresi lambda sebagai berikut:

retryTemplate.execute(arg0 -> { myService.templateRetryService(); return null; }); 

6. Pendengar

Pendengar memberikan panggilan balik tambahan setelah percobaan ulang. Kami dapat menggunakan ini untuk berbagai masalah lintas sektoral di berbagai percobaan ulang.

6.1. Menambahkan Panggilan Balik

Callback disediakan dalam antarmuka RetryListener :

public class DefaultListenerSupport extends RetryListenerSupport { @Override public void close(RetryContext context, RetryCallback callback, Throwable throwable) { logger.info("onClose); ... super.close(context, callback, throwable); } @Override public void onError(RetryContext context, RetryCallback callback, Throwable throwable) { logger.info("onError"); ... super.onError(context, callback, throwable); } @Override public boolean open(RetryContext context, RetryCallback callback) { logger.info("onOpen); ... return super.open(context, callback); } }

The terbuka dan dekat callback datang sebelum dan sesudah seluruh coba lagi, sementara onError berlaku untuk individu RetryCallback panggilan.

6.2. Mendaftarkan Pendengar

Selanjutnya, kami mendaftarkan pendengar kami ( DefaultListenerSupport) ke kacang RetryTemplate kami :

@Configuration public class AppConfig { ... @Bean public RetryTemplate retryTemplate() { RetryTemplate retryTemplate = new RetryTemplate(); ... retryTemplate.registerListener(new DefaultListenerSupport()); return retryTemplate; } }

7. Menguji Hasil

To conclude our example, let's verify the results:

@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; }); } }

As we can see from the test logs, the RetryTemplate and the RetryListener have been properly configured:

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. Conclusion

In this article, we have seen how to use Spring Retry using annotations, the RetryTemplate, and callbacks listeners.

The source code for the examples is available over on GitHub.