Mari kita bicarakan dulu
Baru -baru ini, saya telah mempelajari middleware basis data MySQL open source domestik. Setelah menarik versi terbaru dari kode ke Eclipse, memulainya, dan melakukan berbagai tes dan pelacakan kode. Ketika saya ingin menutupnya setelah menggunakannya, saya mengeluarkan kelas berhenti dan ingin menjalankannya. Saya menemukan bahwa hanya baris kode berikut yang ditulis di kelas ini, jadi saya merasa banyak terluka dalam sekejap.
public static void main (string [] args) {system.out.println (new date () + ", server shutdown!"); }Ketika middleware ini dimulai dan dijalankan, mendengarkan diaktifkan, banyak utas mulai berjalan, dan ada banyak koneksi soket. Tapi tidak ada cara elegan untuk mematikannya. Jadi dengan putus asa, saya hanya bisa pergi ke titik merah kecil gerhana dan dengan paksa menghentikan VM.
Jika itu adalah perangkat lunak dengan arsitektur yang baik, modularitas, dan struktur yang jelas, terutama perangkat lunak seperti server, sangat penting untuk memiliki serangkaian mekanisme manajemen siklus hidup. Tidak hanya dapat mengelola siklus hidup setiap modul, tetapi juga bisa lebih elegan saat memulai dan menghentikan seluruh perangkat lunak tanpa kehilangan sumber daya apa pun.
Implementasi sederhana dari mekanisme siklus hidup
Keadaan siklus hidup
Keadaan siklus hidup suatu modul umumnya memiliki yang berikut:
Bayi Baru Lahir-> Inisialisasi-> Inisialisasi Selesai-> Inisialisasi-> Inisialisasi Selesai-> Inisialisasi-> Inisialisasi-> Jeda-> Pemulihan-> Pemulihan-> Destroy-> Destroy-> Destroying. Jika konversi antara negara bagian mana pun gagal, ia akan memasuki negara lain: kegagalan.
Untuk melakukan ini, Anda dapat menggunakan kelas enumerasi untuk menyebutkan keadaan ini, seperti yang ditunjukkan di bawah ini:
Publik enum lifecyclestate {new, // newsen menginisialisasi, diinisialisasi, // inisialisasi mulai, dimulai, // mulai menangguhkan, ditangguhkan, // jeda melanjutkan, dilanjutkan, // mengembalikan penghancuran, dihancurkan, // hancurkan; // gagal}antarmuka
Berbagai norma perilaku dalam siklus hidup juga membutuhkan antarmuka untuk menentukan, seperti yang ditunjukkan di bawah ini:
Antarmuka publik Ilifecycle { / ** * inisialisasi * * @throws LifeCycleException * / public void init () melempar LifeCycleException; / ** * Mulai * * @throws LifeCycleException */ public void start () melempar LifeCycleException; / ** * Jeda * * @Throws LifeCycleException */ public void suspend () melempar LifeCycleException; / ** * pulih * * @throws LifeCycleException */ public void resume () melempar LifeCycleException; / ** * hancurkan * * @Throws LifeCycleException */ public void hancur () melempar LifeCycleException; / ** * Tambahkan pendengar siklus hidup * * @param listener */ public void addlifecyclelistener (ilifecyclelistener listener); / ** * Hapus pendengar siklus hidup * * @param listener */ public void Removelifecyclelistener (ilifecyclelistener listener);}Ketika transisi keadaan siklus hidup terjadi, pendengar yang tertarik pada jenis peristiwa tertentu mungkin perlu dipicu, sehingga siklus ilifese juga mendefinisikan dua metode untuk menambah dan menghapus pendengar. Mereka adalah: public void addlifecyclelistener (ilifecyclelistener listener); dan public void Removelifecyclelistener (ilifecyclelistener listener);
Pendengar juga mendefinisikan norma perilaku dengan antarmuka, seperti yang ditunjukkan di bawah ini:
Antarmuka publik Ilifecyclelistener { / *** Tangani acara siklus hidup** @param acara siklus hidup* / public void lifecycleevent (LifeCycleEvent Event);}Acara siklus hidup diwakili oleh LifecycleEvent, seperti yang ditunjukkan di bawah ini:
Kelas Akhir Publik LifecycleEvent {swasta lifecyclestate state; siklus hidup publik (status LifeCyclestate) {this.state = state; } / ** * @return state * / public lifecyclestate getState () {return state; }}Implementasi kerangka
Dengan antarmuka IlifeCycle, kelas mana pun yang mengimplementasikan antarmuka ini akan digunakan sebagai objek manajemen siklus hidup. Kelas ini dapat berupa layanan mendengarkan soket, atau dapat mewakili modul tertentu, dll. Jadi, apakah kita hanya perlu menerapkan siklus ilifec? Dapat dikatakan bahwa, tetapi mengingat bahwa setiap objek manajemen siklus hidup akan memiliki beberapa perilaku umum pada berbagai tahap siklus hidup, seperti:
Menetapkan keadaan siklus hidup Anda sendiri untuk memeriksa apakah transisi keadaan sesuai dengan logika untuk memberi tahu pendengar bahwa keadaan siklus hidup telah berubah. Oleh karena itu, sangat penting untuk memberikan siklus abstrak abstrak abstrak sebagai implementasi kerangka siklus ilifes, yang menghindari banyak kode duplikat dan membuat arsitektur lebih jelas. Kelas abstrak ini akan mengimplementasikan semua metode antarmuka yang didefinisikan dalam siklus ilifes dan menambahkan metode abstrak yang sesuai untuk implementasi subkelas. AbstractLifecycle dapat diimplementasikan seperti ini:
Kelas Abstrak Publik Abstrak Abstrak Iklan Ilifecycle {Daftar Privat <Ilifecyclelistener> pendengar = copyonWriteArrayList baru <IlifecycleRistener> (); / *** Negara mewakili keadaan siklus hidup saat ini*/ swasta lifecyclestate state = lifecyclestate.new; / * * @see ilifecycle#init () */ @Override final public final disinkronkan void init () melempar LifeCycleException {if (state! = lifeCyclestate.new) {return; } setstateAndFireEvent (lifecyclestate.initializing); coba {init0 (); } catch (throwable t) {setstateAndFireEvent (lifecyclestate.failed); if (t instance dari LifeCycleException) {throw (LifeCycleException) t; } else {throw new LifeCycleException (formatString ("Gagal menginisialisasi {0}, kesalahan msg: {1}", toString (), t.getMessage ()), t); }} setStateAndFireEvent (lifecyclestate.initialized); } protected abstrak void init0 () melempar LifeCycleException; / * * @see ilifecycle#start () */ @Override public final disinkronkan void start () melempar LifeCycleException {if (state == lifeCyclestate.new) {init (); } if (state! = lifecyclestate.initialized) {return; } setstateAndFireEvent (lifecyclestate.startting); coba {start0 (); } catch (throwable t) {setstateAndFireEvent (lifecyclestate.failed); if (t instance dari LifeCycleException) {throw (LifeCycleException) t; } else {throw new LifeCycleException (formatString ("Gagal memulai {0}, kesalahan msg: {1}", toString (), t.getMessage ()), t); }} setstateAndFireEvent (lifecyclestate.started); } protected abstrak void start0 () melempar LifeCycleException; / * * @see ilifecycle#suspend () */ @Override public final disinkronkan void suspend () melempar LifeCycleException {if (state == lifecyclestate.suspending || state == lifecyclestate.suspended) {return; } if (state! = lifecyclestate.started) {return; } setstateAndFireEvent (lifecyclestate.suspending); coba {suspend0 (); } catch (throwable t) {setstateAndFireEvent (lifecyclestate.failed); if (t instance dari LifeCycleException) {throw (LifeCycleException) t; } else {throw new LifeCycleException (formatString ("Gagal menangguhkan {0}, kesalahan msg: {1}", toString (), t.getMessage ()), t); }} setstateAndFireEvent (lifecyclestate.suspended); } protected abstrak void suspend0 () melempar LifeCycleException; / * * @see ilifecycle#resume () */ @Override final public disinkronkan void resume () melempar LifeCycleException {if (state! = lifeCyclestate.suspended) {return; } setStateAndFireEvent (lifecyclestate.resuming); coba {resume0 (); } catch (throwable t) {setstateAndFireEvent (lifecyclestate.failed); if (t instance dari LifeCycleException) {throw (LifeCycleException) t; } else {throw new LifeCycleException (formatString ("Gagal melanjutkan {0}, kesalahan msg: {1}", toString (), t.getMessage ()), t); }} setStateAndFireEvent (lifecyclestate.resumed); } terlindungi abstrak void resume0 () melempar LifeCycleException; / * * @see ilifecycle#dihancurkan () */ @Override public final disinkronkan void dashar () melempar LifeCycleException {if (state == lifecyclestate.destrroying || state == lifecyclestate.destroyed) {return; } setstateAndFireEvent (lifecyclestate.destroying); coba {dashar0 (); } catch (throwable t) {setstateAndFireEvent (lifecyclestate.failed); if (t instance dari LifeCycleException) {throw (LifeCycleException) t; } else {throw new LifeCycleException (formatString ("Gagal menghancurkan {0}, kesalahan msg: {1}", tostring (), t.getMessage ()), t); }} setStateAndFireEvent (lifecyclestate.destroyed); } protected abstrak void dashar0 () melempar LifecycleException; / * * @see * ilifecycle#addlifecyclelistener (ilifecyclelistener) */ @override void addlifecyclelistener (ilifecyclelistener listener) {listeners.add (pendengar); } /? } private void firelifecycleevent (LifeCycleEvent Event) {for (iterator <lifecyclelistener> it = listeners.iterator (); it.hasnext ();) {ilifecyclistener listener = it.next (); listener.lifecycleevent (acara); }} lifeCyclestate getState yang disinkronkan () {return state; } private disinkronkan void setStateAndFireEvent (LifeCyclestate NewState) melempar LifeCycleException {state = newState; firelifecycleevent (LifecycleEvent baru (negara)); } private string formatString (pola string, objek ... argumen) {return messageFormat.format (pola, argumen); } /? }}Dapat dilihat bahwa implementasi kerangka kelas abstrak melakukan beberapa hal umum dalam manajemen siklus hidup, memeriksa apakah transisi antar negara bagian legal (misalnya, itu harus diinisi sebelum mulai), mengatur keadaan internal, dan memicu pendengar yang sesuai.
Setelah kelas abstrak mengimplementasikan metode yang ditentukan oleh Ilifecycle, ia meninggalkan metode abstrak yang sesuai untuk diterapkan oleh subkelasnya. Seperti yang ditunjukkan pada kode di atas, metode abstrak yang ditinggalkan termasuk yang berikut:
abstrak void init0 yang dilindungi () melempar LifecycleException; abstrak void start0 yang dilindungi () melempar LifecycleException; abstrak abstrak void suspend0 () melempar LifecycleException; abstrak void resume0 yang dilindungi () melempar LifecycleException; abstrak void dashing yang dilindungi () melempar LifecycleException;
Implementasi yang elegan
Sejauh ini, kami telah mendefinisikan antarmuka ilifecycle, dan kerangkanya mengimplementasikan AbstractLifecycle, dan menambahkan mekanisme pendengar. Tampaknya kita dapat mulai menulis kelas untuk mewarisi AbstractLifecycle dan menulis ulang metode abstrak yang ditentukannya, sejauh ini sangat bagus.
Tetapi sebelum kita mulai, kita perlu mempertimbangkan beberapa masalah lain.
Apakah kelas implementasi kami tertarik pada semua metode abstrak?
Apakah setiap implementasi perlu mengimplementasikan init0, start0, suspend0, resume0, hancurkan, dihancurkan0?
Kadang -kadang kelas atau modul hidup kita tidak mendukung suspensi atau pemulihan?
Langsung mewarisi AbstractLifecycle berarti bahwa semua metode abstraknya harus diimplementasikan.
Jadi kita juga membutuhkan implementasi default, siklus default, biarkan itu mewarisi siklus abstrak, dan mengimplementasikan semua metode abstrak, tetapi tidak melakukan apa pun yang praktis, tidak melakukan apa pun. Biarkan saja kelas implementasi nyata mewarisi kelas implementasi default ini dan mengganti metode minat.
Jadi, siklus default kami lahir:
public class DefaultLifecycle extends AbstractLifecycle { /* * @see AbstractLifecycle#init0() */ @Override protected void init0() throws LifecycleException { // do nothing } /* * @see AbstractLifecycle#start0() */ @Override protected void start0() throws LifecycleException { // do nothing } /* * @See AbstractLifeCycle#Suspend0 () */ @Override Protected Void SuspendInternal () melempar LifeCycleException {// Do Nothing}/ * @Lihat Abstrak Abstrak () liftycle#resume0 () */ @Override void resume0 () Lempar LifeCycleException {/ @Override @se @seF () LifeCycle {/ @Override {) {) {/ @Override () lifeCycle {/ @override {) {/ @Override {) {/ @Override {) {) {) @Override Protected Void Destroy0 () melempar LifeCycleException {// Do Nothing}} Untuk siklus default, tidak ada yang bertanggung jawab.
Jadi selanjutnya kita dapat menulis kelas implementasi kita sendiri, mewarisi DefaultLifecycle, dan menulis ulang metode siklus hidup yang menarik.
Misalnya, saya memiliki kelas yang hanya perlu melakukan beberapa tugas selama inisialisasi, startup, dan penghancuran, sehingga saya dapat menulisnya seperti ini:
Impor java.io.ioException; impor java.net.serversocket; impor java.net.socket; socketserver kelas publik memperluas defaultlifecycle {private serversocket akseptor = null; Private int port = 9527; / * * @see defaultLifeCycle#init0 () */ @Override Protected void init0 () melempar LifeCycleException {try {acceptor = new ServerSocket (port); } catch (ioException e) {lempar new LifecycleException (e); }} / * * @see defaultLifeCycle#start0 () * / @Override void start0 () melempar LifeCycleException {socket socket = null; coba {socket = acceptor.accept (); // Lakukan sesuatu dengan socket} catch (ioException e) {lempar new LifecycleException (e); } akhirnya {if (socket! = null) {coba {socket.close (); } catch (ioException e) {// TODO AUTO-ENCEALATED Catch Block E.PrintStackTrace (); }}}}} / * * @see defaultLifeCycle#dashing0 () * / @Override void dash dashing0 () melempar LifeCycleException {if (akseptor! = null) {coba {acceptor.close (); } catch (ioException e) {// TODO AUTO-ENCEALATED Catch Block E.PrintStackTrace (); }}}} Di server di sini, init0 menginisialisasi mendengarkan soket, start0 mulai mendapatkan koneksi soket, dihancurkan penghancuran soket.
Di bawah mekanisme manajemen siklus hidup ini, kami akan dengan mudah mengelola sumber daya, dan tidak akan ada shutdown sumber daya, dan arsitektur dan modularitas akan lebih jelas.
akhir
Sejauh ini, artikel ini telah menerapkan mekanisme manajemen siklus hidup sederhana dan memberikan semua kode implementasi. Setelah itu, semua kode sumber akan ditempatkan di GitHub. Harap perhatikan pembaruan artikel ini.