มาพูดถึงเรื่องนี้ก่อน
เมื่อเร็ว ๆ นี้ฉันได้ศึกษามิดเดิลแวร์ฐานข้อมูลโอเพนซอร์ส MySQL ในประเทศ หลังจากดึงรหัสเวอร์ชันล่าสุดลงไปที่ Eclipse เริ่มต้นและทำการทดสอบและการติดตามรหัสต่างๆ เมื่อฉันต้องการปิดมันหลังจากใช้มันฉันดึงคลาสหยุดและต้องการเรียกใช้ ฉันพบว่ามีเพียงรหัสบรรทัดต่อไปนี้ที่เขียนในชั้นเรียนนี้ดังนั้นฉันรู้สึกว่าฉันได้รับบาดเจ็บมากในทันที
โมฆะคงที่สาธารณะหลัก (สตริง [] args) {system.out.println (วันที่ใหม่ () + ", การปิดเซิร์ฟเวอร์!"); -เมื่อมิดเดิลแวร์นี้เริ่มต้นและเรียกใช้การฟังจะเปิดใช้งานเธรดจำนวนมากเริ่มทำงานและมีการเชื่อมต่อซ็อกเก็ตมากมาย แต่ไม่มีวิธีที่สง่างามในการปิด ดังนั้นด้วยความสิ้นหวังฉันสามารถไปที่จุดสีแดงเล็ก ๆ น้อย ๆ ของคราสและหยุด VM อย่างแรง
หากเป็นซอฟต์แวร์ที่มีสถาปัตยกรรมที่ดีโมดูลาร์และโครงสร้างที่ชัดเจนโดยเฉพาะอย่างยิ่งซอฟต์แวร์ที่มีลักษณะคล้ายเซิร์ฟเวอร์เป็นสิ่งสำคัญมากที่จะต้องมีกลไกการจัดการวงจรชีวิต ไม่เพียง แต่จะสามารถจัดการวงจรชีวิตของแต่ละโมดูลเท่านั้น แต่ยังสามารถสง่างามได้มากขึ้นเมื่อเริ่มต้นและหยุดซอฟต์แวร์ทั้งหมดโดยไม่พลาดทรัพยากรใด ๆ
การใช้กลไกวงจรชีวิตอย่างง่าย
สถานะวงจรชีวิต
สภาพวงจรชีวิตของโมดูลโดยทั่วไปมีดังต่อไปนี้:
ทารกแรกเกิด-> การเริ่มต้น-> การเริ่มต้นเสร็จสิ้น-> การเริ่มต้น-> การเริ่มต้นเสร็จสิ้น-การเริ่มต้น-การเริ่มต้น-> การเริ่มต้น-> หยุด-> การกู้คืน-> การกู้คืน-> ทำลาย-> ทำลาย-> การทำลาย หากการแปลงระหว่างรัฐใด ๆ ล้มเหลวมันจะเข้าสู่สถานะอื่น: ความล้มเหลว
ในการทำเช่นนี้คุณสามารถใช้คลาสการแจงนับเพื่อระบุสถานะเหล่านี้ดังที่แสดงด้านล่าง:
public enum lifecyclestate {ใหม่, // newsen เริ่มต้น, เริ่มต้น, เริ่มต้น, // เริ่มต้นเริ่มต้น, เริ่มต้น, // เริ่มระงับ, ระงับ, // หยุดชั่วคราว, กลับมาทำงานต่อ, // กู้คืนทำลาย, ทำลาย, // ทำลายล้มเหลว; // ล้มเหลว}}ส่วนต่อประสาน
บรรทัดฐานพฤติกรรมต่าง ๆ ในวงจรชีวิตยังต้องใช้อินเทอร์เฟซเพื่อกำหนดดังที่แสดงด้านล่าง:
อินเทอร์เฟซสาธารณะ ilifecycle { / ** * เริ่มต้น * * @throws lifecycleexception * / โมฆะสาธารณะ init () พ่น LifecycleException; / ** * เริ่ม * * @THROWS LifeCycleException */ Public Void Start () พ่น LifecycleException; / ** * หยุดชั่วคราว * * @throws LifecycleException */ โมฆะสาธารณะระงับ () พ่น LifecycleException; / ** * กู้คืน * * @THROWS LifeCycleException */ Public Void Resume () พ่น LifecycleException; / ** * ทำลาย * * @THROWS LifeCycleException */ โมฆะสาธารณะทำลาย () พ่น LifecycleException; / ** * เพิ่ม LifeCycle Listener * * @param Listener */ Public Void AddlifecycleListener (ผู้ฟัง ilifecycleListener); / ** * ลบ Lifecycle Listener * * @param Listener */ Public Void RemoveLifecycleListener (ผู้ฟัง ilifecycleListener);}เมื่อการเปลี่ยนแปลงสถานะวงจรชีวิตเกิดขึ้นผู้ฟังที่มีความสนใจในเหตุการณ์บางประเภทอาจต้องถูกเรียกใช้ดังนั้น ilifecycle จึงกำหนดสองวิธีในการเพิ่มและลบผู้ฟัง พวกเขาคือ: โมฆะสาธารณะ addlifecycleListener (ผู้ฟัง ilifecycleListener); และโมฆะสาธารณะ RemoveLifecycleListener (ผู้ฟัง ilifecycleListener);
ผู้ฟังยังกำหนดบรรทัดฐานพฤติกรรมโดยอินเทอร์เฟซดังที่แสดงด้านล่าง:
อินเทอร์เฟซสาธารณะ ilifecycleListener { / *** จัดการเหตุการณ์วงจรชีวิต** @param เหตุการณ์วงจรเหตุการณ์* / โมฆะสาธารณะ Lifecyclevent (เหตุการณ์ Lifecyclevent);}เหตุการณ์วงจรชีวิตแสดงโดย Lifecyclevent ดังที่แสดงด้านล่าง:
Public Class Lifecyclevent {สถานะ Lifecyclestate ส่วนตัว; Public Lifecyclevent (สถานะ Lifecyclestate) {this.state = state; } / ** * @return สถานะ * / Public Lifecyclestate getState () {return state; -การใช้งานโครงกระดูก
ด้วยอินเทอร์เฟซ Ilifecycle คลาสใดก็ตามที่ใช้อินเทอร์เฟซนี้จะใช้เป็นวัตถุการจัดการวงจรชีวิต คลาสนี้สามารถเป็นบริการฟังซ็อกเก็ตหรือสามารถเป็นตัวแทนของโมดูลเฉพาะ ฯลฯ ดังนั้นเราแค่ต้องใช้ ilifecycle? อาจกล่าวได้ว่า แต่การพิจารณาว่าวัตถุการจัดการวงจรชีวิตแต่ละครั้งจะมีพฤติกรรมร่วมกันบางอย่างในระยะต่าง ๆ ของวงจรชีวิตเช่น:
การตั้งค่าสถานะวงจรชีวิตของคุณเองเพื่อตรวจสอบว่าการเปลี่ยนแปลงของรัฐเป็นไปตามตรรกะเพื่อแจ้งผู้ฟังว่าสถานะวงจรชีวิตมีการเปลี่ยนแปลงหรือไม่ ดังนั้นจึงมีความสำคัญอย่างยิ่งที่จะให้คลาสนามธรรม Abstractlifecycle ในฐานะการใช้โครงกระดูกของ Ilifecycle ซึ่งหลีกเลี่ยงรหัสที่ซ้ำกันจำนวนมากและทำให้สถาปัตยกรรมชัดเจนขึ้น คลาสบทคัดย่อนี้จะใช้วิธีการอินเทอร์เฟซทั้งหมดที่กำหนดไว้ใน iLifecycle และเพิ่มวิธีการนามธรรมที่สอดคล้องกันสำหรับการใช้งาน subclass Abstractlifecycle สามารถนำไปใช้เช่นนี้:
บทคัดย่อระดับสาธารณะ Abstractlifecycle ใช้ ilifecycle {รายการส่วนตัว <IlifecycleListener> Listeners = ใหม่ CopyOnWriteArrayList <IlifecycLelistener> (); / *** สถานะแสดงถึงสถานะวงจรชีวิตปัจจุบัน*/ สถานะ Lifecyclestate ส่วนตัว = Lifecyclestate.new; / * * @See ILIFECYCLE#init () */ @Override สาธารณะสุดท้ายที่ซิงโครไนซ์เป็นโมฆะ init () พ่น LifeCycleException {ถ้า (state! = LifeCyclestate.new) {return; } SetStateAndFireVent (LifeCyclestate.initializing); ลอง {init0 (); } catch (throwable t) {setStateAndFireVent (Lifecyclestate.failed); ถ้า (t อินสแตนซ์ของ LifeCycleException) {โยน (LifecycleException) t; } else {โยน LifecycleException ใหม่ (formatString ("ไม่สามารถเริ่มต้น {0}, ข้อผิดพลาด msg: {1}", toString (), t.getMessage ()), t); }} setStateAndFireVent (LifeCyclestate.initialized); } การป้องกันบทคัดย่อเป็นโมฆะ init0 () โยน Lifecyclexception; / * * @See Ilifecycle#start () */ @Override สาธารณะสุดท้ายที่ซิงโครไนซ์เริ่มต้น () พ่น LifecycleException {if (state == LifeCyclestate.new) {init (); } if (state! = lifecyclestate.initialized) {return; } SetStateAndFireVent (LifeCyclestate.Starting); ลอง {start0 (); } catch (throwable t) {setStateAndFireVent (Lifecyclestate.failed); ถ้า (t อินสแตนซ์ของ LifeCycleException) {โยน (LifecycleException) t; } else {โยน LifecycleException ใหม่ (formatString ("ไม่สามารถเริ่มต้น {0}, ข้อผิดพลาด msg: {1}", toString (), t.getMessage ()), t); }} setStateAndFireVent (LifeCyclestate.Started); } การป้องกันบทคัดย่อเป็นโมฆะ start0 () พ่น LifecycleException; / * * @See ILIFECYCLE#SUSSEDEND () */ @Override สาธารณะสุดท้ายที่ซิงโครไนซ์ sydend () พ่น LifeCycleException {ถ้า (state == Lifecyclestate.Suspending || state == Lifecyclestate.suspended) {return; } if (state! = lifecyclestate.started) {return; } SetStateAndFireVent (LifeCyclestate.Suspending); ลอง {suspend0 (); } catch (throwable t) {setStateAndFireVent (Lifecyclestate.failed); ถ้า (t อินสแตนซ์ของ LifeCycleException) {โยน (LifecycleException) t; } else {โยน LifecycleException ใหม่ (formatString ("ไม่สามารถระงับได้ {0}, ข้อผิดพลาด MSG: {1}", toString (), t.getMessage ()), t); }} setStateAndFireVent (LifeCyclestate.suspended); } การป้องกันบทคัดย่อ void suspend0 () โยน Lifecyclexception; / * * @See Ilifecycle#resume () */ @Override สาธารณะสุดท้ายที่ซิงโครไนซ์ resume () พ่น LifecycleException {ถ้า (state! = LifeCyclestate.suspended) {return; } SetStateAndFireVent (LifeCyclestate.resuming); ลอง {resume0 (); } catch (throwable t) {setStateAndFireVent (Lifecyclestate.failed); ถ้า (t อินสแตนซ์ของ LifeCycleException) {โยน (LifecycleException) t; } else {โยน LifecycleException ใหม่ (formatString ("ล้มเหลวในการดำเนินการต่อ {0}, ข้อผิดพลาด MSG: {1}", toString (), t.getMessage ()), t); }} setStateAndFireVent (LifeCyclestate.resumed); } การป้องกันบทคัดย่อเป็นโมฆะ resume0 () โยน Lifecyclexception; / * * @See ILIFECYCLE#destroy () */ @Override สาธารณะสุดท้ายที่ซิงโครไนซ์เป็นโมฆะทำลาย () พ่น Lifecyctexception {ถ้า (state == Lifecyclestate.Destroying || state == Lifecyclestate.Destroyed) {return; } SetStateAndFireVent (LifeCyclestate.Destroying); ลอง {destroy0 (); } catch (throwable t) {setStateAndFireVent (Lifecyclestate.failed); ถ้า (t อินสแตนซ์ของ LifeCycleException) {โยน (LifecycleException) t; } else {โยน LifecycleException ใหม่ (formatString ("ล้มเหลวในการทำลาย {0}, ข้อผิดพลาด msg: {1}", toString (), t.getMessage ()), t); }} SetStateAndFireVent (Lifecyclestate.Destroyed); } การป้องกันบทคัดย่อโมฆะ destroy0 () โยน Lifecyclexception; / * * @See * ILIFECYCLE#ADDLIFECYCLELISTENER (ILIFECYCLELISTENER) */ @Override โมฆะสาธารณะ AddlifecycleListener (ผู้ฟัง ilifecycleListener) {Listeners.add (ผู้ฟัง); } / * * @See * ILIFECYCLE#RemoVelistener (ILIFECYCLELISTENER) * / @OverRide โมฆะสาธารณะ RemoveLifecyCleListener (ผู้ฟัง ilifecycleListener) {Listeners.Remove (ผู้ฟัง); } โมฆะส่วนตัว FIRELIFECYCLEEVENT (เหตุการณ์ LIFECYCLEEVENT) {สำหรับ (ITERATOR <ILIFECYCLELISTENER> IT = LISSENERS.ITERATOR (); IT.HASNEXT ();) {ILIFECYCLELISTENERER = IT.NEXT (); Listener.lifecycleEvent (เหตุการณ์); }} lifecyclestate ที่ได้รับการป้องกันการซิงโครไนซ์ getState () {return state; } โมฆะส่วนตัวที่ซิงโครไนซ์ SetStateAndFireVent (Lifecyclestate NewState) พ่น LifecycleException {state = newState; FIRELIFECYCLEEVENT (ใหม่ LIFECYCLEEVENT (สถานะ)); } รูปแบบสตริงส่วนตัว (รูปแบบสตริง, วัตถุ ... อาร์กิวเมนต์) {return messageFormat.format (รูปแบบ, อาร์กิวเมนต์); } / * * @See Java.lang.Object#toString () * / @Override สตริงสาธารณะ toString () {return getClass (). getSimplename (); -จะเห็นได้ว่าการใช้โครงกระดูกระดับนามธรรมนั้นทำสิ่งต่าง ๆ ร่วมกันหลายอย่างในการจัดการวงจรชีวิตตรวจสอบว่าการเปลี่ยนแปลงระหว่างรัฐนั้นถูกกฎหมายหรือไม่ (ตัวอย่างเช่นจะต้องเริ่มต้นก่อนเริ่มต้น) การตั้งค่าสถานะภายใน
หลังจากคลาสนามธรรมใช้วิธีการที่กำหนดโดย Ilifecycle มันจะทิ้งวิธีนามธรรมที่สอดคล้องกันสำหรับคลาสย่อยที่จะนำไปใช้ ดังที่แสดงในรหัสด้านบนวิธีการที่เหลืออยู่รวมถึงสิ่งต่อไปนี้:
ได้รับการป้องกันบทคัดย่อช่องว่าง init0 () พ่น Lifecycleexception; ได้รับการป้องกันบทคัดย่อโมฆะ start0 () พ่น Lifecycleexception; ได้รับการป้องกันบทคัดย่อโมฆะ suspend0 () โยน Lifecycleexception; ได้รับการป้องกันบทคัดย่อโมฆะ resume0 () โยน Lifecycleexception; ได้รับการป้องกันบทคัดย่อโมฆะ destroy0 () พ่น Lifecycleexception;
การใช้งานที่หรูหรา
จนถึงตอนนี้เราได้กำหนดอินเทอร์เฟซ ilifecycle และโครงกระดูกของมันใช้ Abstractlifecycle และเพิ่มกลไกการฟัง ดูเหมือนว่าเราสามารถเริ่มเขียนคลาสเพื่อสืบทอด Abstractlifecycle และเขียนวิธีนามธรรมที่กำหนดไว้จนถึงตอนนี้ดีมาก
แต่ก่อนที่เราจะเริ่มเราต้องพิจารณาปัญหาอื่น ๆ อีกมากมาย
คลาสการใช้งานของเรามีความสนใจในทุกวิธีนามธรรมทั้งหมดหรือไม่?
การใช้งานแต่ละครั้งจำเป็นต้องใช้ init0, start0, suspend0, resume0, destroy0, destroy0 หรือไม่?
บางครั้งชั้นเรียนหรือโมดูลที่มีชีวิตของเราไม่สนับสนุนการระงับหรือการกู้คืนหรือไม่?
การสืบทอดโดยตรงกับ Abstractlifecycle หมายความว่าวิธีการนามธรรมทั้งหมดจะต้องดำเนินการ
ดังนั้นเราจึงต้องใช้การใช้งานเริ่มต้น, defaultlifecycle, ปล่อยให้มันสืบทอด Abstractlifecycle และใช้วิธีการนามธรรมทั้งหมด แต่มันไม่ได้ทำอะไรเลยไม่ได้ทำอะไรเลย เพียงให้เราคลาสการใช้งานจริงสืบทอดคลาสการใช้งานเริ่มต้นนี้และแทนที่วิธีที่น่าสนใจ
ดังนั้น lifecycle default ของเราจึงเกิด:
คลาสสาธารณะ defaultLifecycle ขยาย Abstractlifecycle { / * * @See Abstractlifecycle#init0 () * /@Override Void INIT0 () โยน LifecycleException {// ไม่ทำอะไรเลย} / * * @See Abstractlifecycle#start0 () Abstractlifecycle#suspend0 () */ @Override ป้องกันโมฆะ suspendInternal () พ่น lifecycleexception {// ไม่ทำอะไรเลย}/ * * @See Abstractlifecycle#resume0 () */ @Override Void Resume0 () เป็นโมฆะ destroy0 () พ่น LifecycleException {// ไม่ทำอะไรเลย}} สำหรับ DefaultLifecycle ไม่ทำอะไรเลยคือความรับผิดชอบ
ดังนั้นต่อไปเราสามารถเขียนคลาสการใช้งานของเราเองสืบทอด defaultlifecycle และเขียนวิธีการใช้ชีวิตที่น่าสนใจเหล่านั้นใหม่
ตัวอย่างเช่นฉันมีคลาสที่ต้องทำงานบางอย่างระหว่างการเริ่มต้นการเริ่มต้นและการทำลายล้างดังนั้นฉันจึงสามารถเขียนได้เช่นนี้:
นำเข้า java.io.ioException; นำเข้า java.net.serversocket; นำเข้า java.net.socket; Socketserver ระดับสาธารณะขยายค่าเริ่มต้น {ตัวรับเซิร์ฟเวอร์ส่วนตัว = null; พอร์ต int ส่วนตัว = 9527; / * * @See DefaultLifecycle#init0 () */ @Override Void Void Init0 () พ่น LifeCycleException {ลอง {acceptor = ใหม่ Serversocket (พอร์ต); } catch (ioexception e) {โยน LifecycleException ใหม่ (E); }} / * * @See DefaultLifecycle#start0 () * / @Override void protected start0 () พ่น lifecycleexception {ซ็อกเก็ตซ็อกเก็ต = null; ลอง {socket = acceptor.accept (); // ทำอะไรบางอย่างกับซ็อกเก็ต} catch (ioexception e) {โยน LifecycleException ใหม่ (E); } ในที่สุด {ถ้า (ซ็อกเก็ต! = null) {ลอง {socket.close (); } catch (ioexception e) {// todo บล็อก catch block ที่สร้างอัตโนมัติ e.printstacktrace (); }}}}} / * * @See DefaultLifecycle#Destroy0 () * / @Override Void Void Destroy0 () พ่น LifeCycleException {ถ้า (acceptor! = null) {ลอง {acceptor.close (); } catch (ioexception e) {// todo บล็อก catch block ที่สร้างอัตโนมัติ e.printstacktrace (); - ใน Serversocket ที่นี่ Init0 เริ่มต้นการฟังซ็อกเก็ตเริ่มต้นที่จะได้รับการเชื่อมต่อซ็อกเก็ตทำลายการฟังซ็อกเก็ต
ภายใต้กลไกการจัดการวงจรชีวิตนี้เราจะจัดการทรัพยากรได้อย่างง่ายดายและจะไม่มีการปิดทรัพยากรและสถาปัตยกรรมและโมดูลจะชัดเจนขึ้น
จบ
จนถึงตอนนี้บทความนี้ได้ใช้กลไกการจัดการวงจรชีวิตอย่างง่ายและให้รหัสการใช้งานทั้งหมด หลังจากนั้นซอร์สโค้ดทั้งหมดจะถูกวางไว้บน GitHub โปรดให้ความสนใจกับการอัปเดตของบทความนี้