Spring retry เป็นฟังก์ชั่นพลังงานที่เป็นอิสระจากชุดฤดูใบไม้ผลิซึ่งส่วนใหญ่ใช้การลองใหม่และฟิวส์ มีข้อ จำกัด สถานการณ์สำหรับการลองใหม่และไม่ใช่ทุกสถานการณ์ที่เหมาะสำหรับการลองใหม่เช่นการตรวจสอบพารามิเตอร์ที่ผิดกฎหมายการดำเนินการเขียน ฯลฯ (คุณต้องพิจารณาว่าการเขียนนั้นเป็น idempotent) ไม่เหมาะสำหรับการลองใหม่ การหมดเวลาการโทรระยะไกลหรือการหยุดชะงักของเครือข่ายสามารถลองใหม่ได้อีกครั้ง ในกรอบการกำกับดูแล Microservice มักจะมีการกำหนดค่าการลองใหม่และการหมดเวลาของตัวเอง ตัวอย่างเช่น Dubbo สามารถตั้งค่า retries = 1, timeout = 500 การโทรล้มเหลวและลองอีกครั้งเพียงครั้งเดียวและการโทรล้มเหลวหากไม่กลับมาหลังจากผ่านไปมากกว่า 500ms ในฤดูใบไม้ผลิลองใหม่คุณสามารถระบุประเภทของข้อยกเว้นที่ต้องลองใหม่และตั้งค่าช่วงเวลาสำหรับการลองใหม่และหากการลองใหม่ล้มเหลวไม่ว่าจะลองดำเนินการต่อหรือฟิวส์ต่อไป
การออกแบบและการดำเนินการ
RetryOperations กำหนด API ใหม่ RetryTemplate เป็นการใช้งานโหมดเทมเพลตของ API ซึ่งใช้การลองใหม่และทำลายวงจร API ที่ให้ไว้มีดังนี้:
อินเทอร์เฟซสาธารณะ retryoperations {<t, e ขยายได้> t execute (retryCallback <t, e> retryCallback) โยน e; } // API อื่น ๆ ถูกละไว้ RetryCallback กำหนดการดำเนินการที่ต้องดำเนินการ หลังจากกำหนดการดำเนินการมันเป็นคำถามของวิธีการลองใหม่ RetryTemplate ดำเนินการตรรกะของวิธีการลองใหม่โดยการกำหนดกลยุทธ์การลองใหม่ที่แตกต่างกัน กลยุทธ์การลองใหม่เริ่มต้นนั้น SimpleRetryPlicy ซึ่งหมายความว่าจะลองใหม่ 3 ครั้ง หากการลองใหม่ประสบความสำเร็จคุณจะไม่ลองอีกครั้ง แล้วถ้าการลอง 3 ฟุตล้มเหลวล่ะ? กระบวนการสิ้นสุดหรือส่งคืนผลลัพธ์จากล่างขึ้นบน ในการส่งคืนผลลัพธ์จากล่างขึ้นบนคุณจะต้องกำหนดค่า RecoveyCallBack จากชื่อคุณจะเห็นว่านี่เป็นอินเทอร์เฟซการโทรกลับจากล่างขึ้นบนซึ่งเป็นตรรกะของการดำเนินการหลังจากการลองใหม่ล้มเหลว นอกเหนือจาก SimpleRetryPolicy ยังมีกลยุทธ์การลองใหม่อื่น ๆ มาดูอินเทอร์เฟซ RetryPolicy :
ส่วนต่อประสานสาธารณะ RetryPolicy ขยาย serializable {boolean canretry (บริบท retryContext); retryContext เปิด (RetryContext Parent); เป็นโมฆะปิด (บริบท retryContext); เป็นโมฆะ registerthrowable (บริบท retrycontext, throwable throwable);} canRetry เรียกว่าทุกครั้งที่คุณลองอีกครั้ง เงื่อนไขการตัดสินว่าคุณสามารถลองอีกครั้งต่อไปได้หรือไม่
เรียกว่าก่อนที่จะเริ่มต้นใหม่ open บริบทการลองใหม่จะถูกสร้างขึ้นไปยัง RetryContext และจะบันทึกสแต็กลองอีกครั้ง
registerThrowable เรียกว่าทุกครั้งที่มีการลองใหม่ (มีข้อยกเว้นและจะดำเนินการต่อไปอีกครั้ง)
ใช้ตัวอย่าง SimpleRetryPolicy เป็นตัวอย่าง เมื่อจำนวนการลองใหม่ถึง 3 (เริ่มต้น 3 ครั้ง) ให้หยุดการลองใหม่และจำนวนการลองใหม่จะถูกบันทึกไว้ในบริบทของการลองใหม่
ให้การใช้กลยุทธ์การลองใหม่ต่อไปนี้:
ลองใช้กลยุทธ์ทางเลือกอีกครั้งหมายถึงว่าการลองใหม่แต่ละครั้งจะลองใหม่ทันทีหรือรอสักครู่ก่อนที่จะลองอีกครั้ง โดยค่าเริ่มต้นคุณจะต้องระบุนโยบาย backoff BackoffRetryPolicy หากคุณต้องการกำหนดค่าระยะเวลารอและลองอีกครั้ง BackoffretryPolicy มีการนำไปใช้ดังต่อไปนี้:
retry retry stateful หรือ retry ไร้สัญชาติ
การลองใหม่ที่เรียกว่าไม่มีสัญลักษณ์หมายถึงการลองใหม่ในบริบทของเธรด มิฉะนั้นหากลองทำซ้ำในบริบทของเธรดจะเป็นการลองอีกครั้ง SimpleRetryPolicy ก่อนหน้านี้คือการลองใหม่ที่ไร้สัญชาติเพราะลองเสร็จสิ้นในลูป แล้วจะเกิดอะไรขึ้นหลังจากนั้นหรือจำเป็นต้องลองใหม่ในรัฐ? โดยปกติจะมีสองสถานการณ์: การทำธุรกรรมย้อนกลับและเบรกเกอร์
DataAccessException นั้นยอดเยี่ยม ไม่สามารถลองใหม่ได้ แต่หากมีการโยนข้อยกเว้นอื่น ๆ คุณสามารถลองอีกครั้ง
ฟิวส์หมายถึงการไม่จัดการใหม่ในลูปปัจจุบัน แต่ไปยังโหมดการลองใหม่ทั่วโลก (ไม่ใช่บริบทเธรด) เบรกเกอร์จะกระโดดออกจากวงและข้อมูลสแต็กของบริบทเธรดจะหายไปอย่างหลีกเลี่ยงไม่ได้ จากนั้นจำเป็นอย่างยิ่งที่จะต้องบันทึกข้อมูลนี้ใน "โหมดทั่วโลก" การใช้งานปัจจุบันถูกวางไว้ในแคช (การใช้งานแผนที่) คุณสามารถลองอีกครั้งหลังจากได้รับจากแคชในครั้งต่อไป
เริ่มต้นอย่างรวดเร็ว
ใช้ @EnableRetry ในคลาสที่ต้องดำเนินการลองใหม่หาก proxyTargetClass=true ถูกตั้งค่านี้ใช้ CGLIB Dynamic Proxy:
@configuration@enableRetry (proxyTargetClass = true) @componentpublic คลาส retryExamples {} ลองใหม่ตามจำนวนกลยุทธ์การลองใช้ใหม่สูงสุดหากการลองซ้ำซ้ำ 3 ครั้งและข้อยกเว้นยังคงถูกโยนลงไปการลองใหม่จะหยุดลงและการเรียกกลับจากล่างขึ้นบนจะถูกดำเนินการ ดังนั้นผลลัพธ์ผลลัพธ์สุดท้ายคือ Integer.MAX_VALUE :
โมฆะส่วนตัว retryExample3 () โยนข้อยกเว้น {retryTemplate retryTemplate = ใหม่ retryTemplate (); simpleeretryPolicy simpleeretryPolicy = new SimpleRetryPolicy (); SimpleeretryPolicy.SetMaxAttempts (3); retrytemplate.setretrypolicy (simpleeretrypolicy); integer result = retryTemplate.execute (ใหม่ retryCallback <จำนวนเต็ม, ข้อยกเว้น> () {int i = 0; // retry การดำเนินการ @Override จำนวนเต็มสาธารณะ dowithRetry (retryContext retryContext) RecoveryCallback <Integer> () {// การเรียกกลับ base @Override การกู้คืนสาธารณะ (retryContext retryContext) โยนข้อยกเว้น {log.info ("หลังจากลองใหม่: {}, วิธีการกู้คืนที่เรียกว่า!" log.info ("ผลลัพธ์สุดท้าย: {}", ผลลัพธ์); } int ส่วนตัว len (int i) โยนข้อยกเว้น {ถ้า (i <10) โยนข้อยกเว้นใหม่ (i + "le 10"); กลับฉัน; -ต่อไปนี้อธิบายถึงวิธีการใช้โหมดนโยบาย Circuit Breaker retry (CircuitBreakerRetryPolicy) ต้องตั้งค่าพารามิเตอร์สามตัวต่อไปนี้:
การเปิดและปิดการตัดสินของวงจร:
รหัสทดสอบมีดังนี้:
เทมเพลต retryTemplate = ใหม่ retrytemplate (); CircuitBreakerRetryPolicy RetryPolicy = ใหม่ CircuitBreakerRetryPolicy (ใหม่ SimpleRetryPolicy (3)); retrypolicy.setopentimeout (5,000); retrypolicy.setResetTimeOut (20000); template.setRetryPolicy (retrypolicy); สำหรับ (int i = 0; i <10; i ++) {//thread.sleep(100); ลอง {object key = "วงจร"; บูลีน isforcerefresh = false; retrystate state = ใหม่ defaultretrystate (คีย์, isforcerefresh); String result = template.execute (ใหม่ retryCallback <String, runtimeException> () {@Override สตริงสาธารณะ dowithRetry (บริบท retryContext) โยน runtimeException {log.info ("retry count: {}", บริบท {@Override สตริงสาธารณะกู้คืน (บริบท retryContext) โยนข้อยกเว้น {return "default";}}, สถานะ); log.info ("ผลลัพธ์: {}", ผลลัพธ์); } catch (exception e) {system.out.println (e); - เนื่องจากตั้งค่า isForceRefresh = false ค่าของ key = "circuit" (นั่นคือ retryContext) จะได้รับจากแคช ดังนั้นเมื่อการลองใหม่ล้มเหลวและ this.time < this.openWindow จะถูกหลอมรวมคุณยังคงสามารถใช้งานใหม่ในโหมดทั่วโลก ( RetryContext ที่ได้รับเหมือนกัน)
การพัฒนาคำอธิบายประกอบ
หากการเขียน RetryTemplate ทุกครั้งที่คุณมีข้อกำหนดการลองใหม่จะป่องเกินไปการใช้คำอธิบายประกอบสามารถทำให้การพัฒนาง่ายขึ้นและลดรหัสที่ซ้ำกันอย่างมาก นี่คือการลองกลยุทธ์การลองใหม่สูงสุดที่ใช้โดยใช้คำอธิบายประกอบ:
@Retryable (value = sqldataException.class, backoff = @backoff (value = 0l)) บริการสตริงสาธารณะ 3 () พ่น sqldataexception {log.info ("Service3 Open"); โยน sqldataexception ใหม่ (); } @Recover Public String กู้คืน (SQLDATAException NE) {return "sqldataException กู้คืน"; -คำอธิบายประกอบ ได้แก่ :
@enableretry
@retryable
@ฟื้นตัว
@backoff
@circuitbreaker
@Enableretry: ลองอีกครั้งได้ไหม เมื่อคุณสมบัติ proxytargetClass เป็นจริง (ค่าเริ่มต้นเท็จ) ให้ใช้ cGlib proxy
@Retryable: วิธีการที่ต้องมีคำอธิบายประกอบใหม่
@backoff: ลองใช้กลยุทธ์ทางเลือก (ลองตอนนี้หรือรอสักครู่ก่อนที่จะลองอีกครั้ง)
@Recover: สำหรับใช้กับวิธีการ ใช้เป็นวิธี "รับประกัน" เมื่อ @retryable ล้มเหลว วิธีการแสดงความคิดเห็น @Recover ต้องสอดคล้องกับวิธีการ "ลายเซ็น" ของคำอธิบายประกอบ @Retryable พารามิเตอร์รายการแรกเป็นข้อยกเว้นที่จะลองใหม่ พารามิเตอร์อื่น ๆ สอดคล้องกับ @Retryable ค่าส่งคืนจะต้องเหมือนกันมิฉะนั้นจะไม่สามารถดำเนินการได้!
@CircuitBreaker: ใช้สำหรับวิธีการใช้โหมดการทำลายวงจร
สำหรับตัวอย่างเพิ่มเติมยินดีต้อนรับสู่ GitHub ของฉัน (https://github.com/happyxiaofan/springboot-learning-example) ดาว ขอบคุณ
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่ามันจะเป็นประโยชน์ต่อการเรียนรู้ของทุกคนและฉันหวังว่าทุกคนจะสนับสนุน wulin.com มากขึ้น