Spring Retry adalah fungsi energi yang independen dari batch pegas, yang terutama mengimplementasikan coba lagi dan sekering. Ada pembatasan skenario untuk coba lagi, dan tidak semua skenario cocok untuk coba lagi, seperti verifikasi parameter ilegal, operasi tulis, dll. (Anda perlu mempertimbangkan apakah penulisannya idempoten) tidak cocok untuk dicoba lagi. Timeout panggilan jarak jauh atau gangguan jaringan dapat dicetak ulang. Dalam kerangka tata kelola layanan mikro, biasanya memiliki konfigurasi coba lagi dan waktu tunggu. Misalnya, Dubbo dapat mengatur retries = 1, timeout = 500 panggilan gagal dan coba lagi sekali, dan panggilan gagal jika tidak kembali setelah lebih dari 500ms. Di Spring Retry Anda dapat menentukan jenis pengecualian yang perlu dicoba lagi, dan mengatur interval untuk setiap coba lagi dan jika coba lagi gagal, apakah akan terus mencoba lagi atau sekering (berhenti coba lagi).
Desain dan Implementasi
RetryOperations mendefinisikan RETRY API. RetryTemplate adalah implementasi mode templat dari API, yang mengimplementasikan coba lagi dan memecahkan sirkuit. API yang disediakan adalah sebagai berikut:
Retryoperations Antarmuka Publik {<t, e memperluas yang dapat dilaksanakan> t dieksekusi (retrycallback <t, e> retrycallback) melempar e; } // API lainnya telah dihilangkan RetryCallback mendefinisikan operasi yang perlu dilakukan. Setelah mendefinisikan operasi, itu adalah pertanyaan tentang cara mencoba lagi. RetryTemplate menjalankan logika cara mencoba lagi dengan merumuskan strategi coba lagi yang berbeda. Strategi RETRY Default adalah SimpleRetryPlicy , yang berarti akan diceritakan kembali 3 kali. Jika coba lagi berhasil, Anda tidak akan terus mencoba lagi. Jadi bagaimana jika 3 kaki coba lagi gagal? Proses mengakhiri atau mengembalikan hasil bottom-up. Untuk mengembalikan hasil bottom-up, Anda perlu mengkonfigurasi RecoveyCallBack . Dari namanya, Anda dapat melihat bahwa ini adalah antarmuka callback bottom-up, yang merupakan logika eksekusi setelah coba lagi gagal. Selain SimpleRetryPolicy , ada strategi coba lagi. Mari kita lihat antarmuka RetryPolicy :
antarmuka publik Retrypolicy memperluas serial {boolean canretry (retrycontext konteks); RetryContext Open (RetryContext Parent); void close (retrycontext konteks); void Registerthrowable (RetryContext Context, Throwable Throwable);} canRetry dipanggil setiap kali Anda mencoba lagi. Kondisi penilaian apakah Anda dapat terus mencoba lagi
Dipanggil sebelum open Retry dimulai, konteks coba lagi akan dibuat ke RetryContext , dan Retry Stack akan disimpan.
registerThrowable dipanggil setiap kali pengecualian dicoba lagi (ada pengecualian dan akan terus mencoba lagi)
Ambil SimpleRetryPolicy sebagai contoh. Ketika jumlah retry mencapai 3 (default 3 kali), berhenti mencoba lagi, dan jumlah coba lagi disimpan dalam konteks coba lagi.
Berikan implementasi strategi coba lagi berikut:
Coba lagi strategi fallback mengacu pada apakah setiap coba lagi segera atau tunggu sebentar sebelum mencoba lagi. Secara default, Anda perlu menentukan BackoffRetryPolicy kebijakan backoff jika Anda perlu mengonfigurasi masa tunggu dan kemudian mencoba lagi. Backoffretrypolicy memiliki implementasi berikut:
Coba lagi atau coba lagi
Retry tanpa kewarganegaraan yang disebut mengacu kembali yang diselesaikan dalam konteks utas. Kalau tidak, jika coba lagi yang tidak diselesaikan dalam konteks utas adalah coba lagi. SimpleRetryPolicy sebelumnya adalah coba lagi karena coba lagi selesai dalam satu loop. Jadi apa yang terjadi setelah itu atau perlu dikembalikan dalam keadaan? Biasanya ada dua situasi: transaksi rollback dan pemutus sirkuit.
DataAccessException luar biasa. Coba lagi tidak dapat dilakukan, tetapi jika pengecualian lain dilemparkan, Anda dapat mencoba lagi.
Fuse berarti tidak menangani coba lagi di loop saat ini, tetapi untuk mode coba lagi global (bukan konteks utas). Pemutus sirkuit akan melompat keluar dari loop, dan informasi tumpukan konteks utas pasti akan hilang. Maka pasti perlu untuk menyimpan informasi ini dalam "mode global". Implementasi saat ini ditempatkan dalam cache (implementasi MAP). Anda dapat terus mencoba lagi setelah mendapatkannya dari cache lain kali.
Awal yang cepat
Gunakan @EnableRetry pada kelas yang perlu dilakukan Retry, jika proxyTargetClass=true diatur, ini menggunakan proxy dinamis CGLIB:
@Configuration@enableretry (proxyTargetClass = true) @ComponentPublic kelas retryexamples {} Coba lagi berdasarkan jumlah maksimum strategi retries, jika coba lagi diulang 3 kali dan pengecualian masih dilemparkan, coba lagi dihentikan dan panggilan balik bottom-up dijalankan. Oleh karena itu, hasil output akhir adalah Integer.MAX_VALUE :
private void retryexample3 () melempar pengecualian {retrytemplate retrytemplate = retrytemplate baru (); SimpleretryPolicy SimpleretryPolicy = new SimpleretryPolicy (); SimpleretryPolicy.SetMaxAttempts (3); retrytemplate.setRetrypolicy (SimpleretryPolicy); Integer hasil = retrytemplate.execute (retrycallback baru <integer, exception> () {int i = 0; // coba lagi operasi @override public integer dowithretry (retrycontext retrycontext) lempar pengecualian {log.info ("jumlah retry: {},}, retrycet. }}, RecoveryCallback baru <Integer> () {// base callback @Override Public Integer Recover (RetryContext RetryContext) melempar Exception {log.info ("setelah RETRY: {}, REGORTING DAPATKAN!", log.info ("Hasil akhir: {}", hasilnya); } private int len (int i) melempar pengecualian {if (i <10) melempar pengecualian baru (i + "le 10"); Kembalikan i; }Berikut ini menjelaskan cara menggunakan mode kebijakan pemutus pemutus sirkuit (sirkuitbreakerretrypolicy). Tiga parameter berikut perlu diatur:
Pembukaan pemutus sirkuit dan penutupan penilaian:
Kode tes adalah sebagai berikut:
Template RetryTemplate = RetryTemplate baru (); Sirkuitbreakerretrypolicy retrypolicy = new CircuitbreakerretryPolicy (new SimpleretryPolicy (3)); retrypolicy.setopentimeout (5000); Retrypolicy.SetResetTimeout (20000); template.setretrypolicy (retrypolicy); untuk (int i = 0; i <10; i ++) {//thread.sleep(100); coba {objek key = "sirkuit"; boolean isforcerefresh = false; Retrystate state = DEFAULTRETREDSTATE BARU (Key, ISFORCEREFRESH); String result = template.execute (retrycallback baru <string, runimeException> () {@Override public string dowithretry (retrycontext konteks) melempar runtimeeException {log.info ("retry count: {}", context.getRetrycount (); new runime runime: {}, context.getretcount (); new runime runime: {{}, context.getretcount (); RecoveryCallback <String> () {@Override Public String Recover (RetryContext Context) melempar Exception {return "default"; log.info ("hasil: {}", hasilnya); } catch (Exception e) {System.out.println (e); }} Karena isForceRefresh = false diatur, nilai key = "circuit" (yaitu, retrycontext) akan diperoleh dari cache. Oleh RetryContext itu, ketika coba lagi gagal dan this.time < this.openWindow
Pengembangan Anotasi
Jika menulis RetryTemplate setiap kali Anda memiliki persyaratan coba lagi terlalu membengkak, menggunakan anotasi dapat sangat menyederhanakan pengembangan dan mengurangi kode duplikat. Berikut adalah coba lagi strategi coba lagi yang diimplementasikan menggunakan anotasi:
@Retryable (value = sqldataException.class, backoff = @backoff (value = 0l)) public string service3 () melempar sqldataException {log.info ("service3 open"); lempar sqldataException baru (); } @Recover string public recover (sqldataException ne) {return "sqldataException Recover"; }Anotasi meliputi:
@Enableretry
@Retryable
@Pulih
@Backoff
@Circuitbreaker
@Enableretry: Bisakah Anda mencoba lagi? Ketika properti ProxyTargetClass benar (default false), gunakan proxy cglib
@Retryable: Metode anotasi perlu dicoba lagi
@Backoff: Coba lagi strategi fallback (coba sekarang atau tunggu sebentar sebelum mencoba lagi)
@Recover: Untuk digunakan dengan metode. Digunakan sebagai metode "dijamin" ketika @Retryable gagal. Metode anotasi @Recover harus konsisten dengan metode "tanda tangan" anotasi @Retryable. Parameter entri pertama adalah pengecualian yang akan dikembalikan. Parameter lain konsisten dengan @etryable. Nilai pengembalian harus sama, jika tidak, itu tidak dapat dieksekusi!
@Circuitbreaker: Digunakan untuk metode, implementasikan mode pemecahan sirkuit.
Untuk contoh lebih lanjut, selamat datang di GitHub saya (https://github.com/happyxiaofan/springboot-learning-example). Terima kasih
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.