Hablemos de eso primero
Recientemente, he estado estudiando un middleware de base de datos MySQL de código abierto nacional. Después de retirar su última versión del código para eclipsar, comenzar y hacer varias pruebas y seguimiento de código. Cuando quiero cerrarlo después de usarlo, saco su clase de parada y quiero ejecutarlo. Descubrí que solo las siguientes líneas de código estaban escritas en esta clase, por lo que sentí que me lastimaba mucho en un instante.
public static void main (string [] args) {system.out.println (new Date () + ", Servidor Sechney!"); }Cuando se inicia y se ejecuta este middleware, la escucha está habilitada, se inician muchos hilos y hay muchas conexiones de socket. Pero no hay una forma elegante de apagarlo. Entonces, en desesperación, solo podía ir al pequeño punto rojo de Eclipse y detener con fuerza la VM.
Si se trata de un software con una buena arquitectura, modularidad y estructura clara, especialmente un software similar al servidor, es muy importante tener un conjunto de mecanismos de gestión del ciclo de vida. No solo puede administrar el ciclo de vida de cada módulo, sino que también puede ser más elegante al comenzar y detener todo el software sin perder ningún recurso.
Implementación simple del mecanismo del ciclo de vida
Estado del ciclo de vida
El estado del ciclo de vida de un módulo generalmente tiene lo siguiente:
Recién nacido-> inicialización-> inicialización completada-> inicialización-> inicialización completada-> inicialización-> inicialización-> pausa-> recuperación-> recuperación-> destruir-> destruir-> destruir. Si la conversión entre los estados falla, ingresará a otro estado: falla.
Para hacer esto, puede usar una clase de enumeración para enumerar estos estados, como se muestra a continuación:
public enum lifecyClestate {nuevo, // Newsen Inicialización, inicializada, // Inicializar el inicio, iniciado, // Comienza a suspender, suspender, // Pausa reanudando, reanudada, // restaurar la destrucción, destruida, // destruir fallida; // falló}interfaz
Varias normas de comportamiento en el ciclo de vida también requieren una interfaz para definir, como se muestra a continuación:
interfaz pública ilifecycle { / ** * inicialize * * @throws lifecycleException * / public void init () lanza lifecycleException; / ** * inicio * * @throws lifecycleException */ public void start () lanza lifecycleException; / ** * pausa * * @throws lifecycleException */ public void suspend () lanza lifecycleException; / ** * recuperar * * @throws lifecycleException */ public void resume () lanza lifecycleException; / ** * destruir * * @throws lifecycleException */ public void destruye () lanza lifecycleException; / ** * Agregar Lifecycle Listener * * @param Listener */ public void addlifecyclelistener (IlifecyClelistener Listener); / ** * Eliminar el oyente del ciclo de vida * * @param oyente */ public void removelifecyClelistener (IlifecyClelistener oyente);}Cuando se produce una transición de estado de ciclo de vida, es posible que deban activarse los oyentes interesados en un cierto tipo de evento, por lo que Ilifecycle también define dos métodos para agregar y eliminar los oyentes. Ellos son: public void addlifecyclelistener (oyente ilifecyclelistener); y public void RemoVelifecyClelistener (Ilifecyclelistener oyente);
El oyente también define sus normas de comportamiento por una interfaz, como se muestra a continuación:
interfaz pública ilifecyclelistener { / *** manejar eventos de ciclo de vida** @param eventos de ciclo de vida* / public void lifecycleEvent (lifecycleEvent Event);}Los eventos del ciclo de vida están representados por LifeCycleEvent, como se muestra a continuación:
Public Final Clase LifecycleEvent {estado privado de tipo de vida de vida; Public LifeCycleEvent (LifecyClestate State) {this.state = state; } / ** * @return the state * / public lifecyClestate getState () {return state; }}Implementación del esqueleto
Con la interfaz Ilifecycle, cualquier clase que implementa esta interfaz se utilizará como objeto de gestión del ciclo de vida. Esta clase puede ser un servicio de escucha de socket, o puede representar un módulo específico, etc. Entonces, ¿solo necesitamos implementar Ilifecycle? Se puede decir que, pero teniendo en cuenta que cada objeto de gestión del ciclo de vida tendrá algunos comportamientos comunes en varias etapas del ciclo de vida, tales como:
Establecer su propio estado del ciclo de vida para verificar si la transición del estado se ajusta a la lógica para notificar al oyente que el estado del ciclo de vida ha cambiado. Por lo tanto, es de gran importancia proporcionar una clase abstracta abstractlifecycle como la implementación esquelética de Ilifecycle, que evita mucho código duplicado y deja la arquitectura más clara. Esta clase abstracta implementará todos los métodos de interfaz definidos en Ilifecycle y agregará métodos abstractos correspondientes para la implementación de la subclase. AbstractLifecycle se puede implementar así:
Public Abstract Class AbstractLifeCycle implementa Ilifecycle {Lista privada <IlifecyClelistener> oyentes = new CopyOnWriteArrayList <IlifecyClelistener> (); / *** El estado representa el estado de ciclo de vida actual*/ estado de vida de vida privado = lifecyClestate.new; / * * * @see ilifecycle#init () */ @Override público sincronizado sincronizado init () arroja lifecycleException {if (state! = lifecyClestate.new) {return; } setstateAndFireeVent (lifecyClestate.initializing); intente {init0 (); } catch (Throwable t) {setSteeAndFireEsevent (lifecyClestate.failed); if (t instancia de lifecycleException) {throw (lifecycleException) t; } else {lanzar nueva lifeCycleException (formatString ("no pudo inicializar {0}, error msg: {1}", toString (), t.getMessage ()), t); }} setSteeandFireeVevent (lifecyClestate.initialized); } Resumen protegido Void init0 () lanza LifeCycleException; / * * * @see ilifecycle#start () */ @Override público sincronizado sincronizado start () arroja lifecycleException {if (state == lifecyClestate.new) {init (); } if (state! = lifecyClestate.initialized) {return; } setSteeandFireeVent (LifeCyClestate.Starting); intente {start0 (); } catch (Throwable t) {setSteeAndFireEsevent (lifecyClestate.failed); if (t instancia de lifecycleException) {throw (lifecycleException) t; } else {lanzar nueva lifecycleException (formatString ("Error al comenzar {0}, error msg: {1}", toString (), t.getMessage ()), t); }} setSteeandFireeVent (LifeCyClestate.Started); } protegido abstracto void start0 () arroja lifecycleException; / * * @see ilifecycle#suspend () */ @Override público sincronizado sincronizado suspend () arroja lifecycleException {if (state == lifecyclestate.suspending || state == lifecyclestate.suspended) {retorno; } if (state! = lifecyClestate.StarDed) {return; } setSteeandFireeVent (lifecyClestate.suspending); intente {suspender0 (); } catch (Throwable t) {setSteeAndFireEsevent (lifecyClestate.failed); if (t instancia de lifecycleException) {throw (lifecycleException) t; } else {lanzar nueva lifecycleException (formatString ("no se pudo suspender {0}, error msg: {1}", toString (), t.getMessage ()), t); }} setSteeandFireeVevent (lifecyClestate.suspended); } Resumen protegido Void Suspend0 () lanza LifeCycleException; / * * @see ilifecycle#resume () */ @Override público sincronizado sincronizado currume () arroja lifecycleException {if (state! = lifecyClestate.suspended) {return; } setSteeandFireeVent (lifecyClestate.resuming); intente {reume0 (); } catch (Throwable t) {setSteeAndFireEsevent (lifecyClestate.failed); if (t instancia de lifecycleException) {throw (lifecycleException) t; } else {lanzar nueva lifecycleException (formatString ("no se puede reanudar {0}, error msg: {1}", toString (), t.getMessage ()), t); }} setSteeandFireeVevent (LifeCyClestate.Resumed); } Resumen abstracto protegido 0 () arroja lifecycleException; / * * @see ilifecycle#destruye () */ @Override público sincronizado sincronizado destruye () arroja lifecycleException {if (state == lifecyClestate.destroying || state == lifecyClestate.destroyed) {return; } setSteeandFireeVent (lifecyClestate.destroying); intente {Destroy0 (); } catch (Throwable t) {setSteeAndFireEsevent (lifecyClestate.failed); if (t instancia de lifecycleException) {throw (lifecycleException) t; } else {lanzar nueva lifeCycleException (formatString ("Error al destruir {0}, error de error: {1}", toString (), t.getMessage ()), t); }} setSteeandFireeVevent (lifecyClestate.destroyed); } Programa abstracto protegido Destroy0 () arroja LifeCycleException; / * * * @see * ilifecycle#addlifecycleListener (ilifecyclelistener) */ @Override public void addlifecyclelistener (IlifecyClelistener oyente) {oyentes.add (oyente); } / * * * @see * ilifecycle#removeListener (ilifecycleListener) * / @Override public void RemoVelifecyClelistener (IlifecycleListener oyente) {oyentes.remove (oyente); } private void firelifecycleEvent (LifeCycleEvent Event) {for (iterator <IlifeCyClelistener> it = oyentes.iterator (); it.hasnext ();) {ilifecyclelistener oyente = it.next (); oyente.lifecycleEvent (evento); }} protegido LifeCyClestate GetState () {Estado de retorno; } Void sincronizado privado setstateAndFireeVevent (LifeCyClestate NewState) arroja lifecycleException {state = newState; FirElifecycleEvent (New LifecycleEvent (estado)); } private String formatString (patrón de cadena, objeto ... argumentos) {return MessageFormat.format (patrón, argumentos); } / * * @see java.lang.object#toString () * / @Override public string toString () {return getClass (). getSimplename (); }}Se puede ver que la implementación del esqueleto de clase abstracta hace varias cosas comunes en el manejo del ciclo de vida, verificando si la transición entre los estados es legal (por ejemplo, debe ser init antes del inicio), establecer el estado interno y activar el oyente correspondiente.
Después de que la clase abstracta implementa el método definido por Ilifecycle, deja los métodos abstractos correspondientes para que su subclase se implemente. Como se muestra en el código anterior, los métodos abstractos que dejan fuera incluyen lo siguiente:
Resumen protegido Void init0 () lanza LifecycleException; Programa abstracto protegido Start0 () arroja LifeCycleException; Programa abstracto protegido suspend0 () arroja lifecycleException; resumido abstracto protegido 0 () arroja LifeCycleException; Pro abstracto protegido Destroy0 () arroja lifecycleException;
Implementación elegante
Hasta ahora, hemos definido la interfaz ilifecycle, y su esqueleto implementa abstractlifecycle, y agregó un mecanismo del oyente. Parece que podemos comenzar a escribir una clase para heredar AbstractLifecycle y reescribir el método abstracto que define, hasta ahora todo bien.
Pero antes de comenzar, debemos considerar varios otros problemas.
¿Nuestras clases de implementación están interesadas en todos los métodos abstractos?
¿Cada implementación necesita implementar init0, start0, suspender0, reanudar0, destruir0, destruir0?
¿A veces nuestras clases o módulos de vida no admiten la suspensión o la recuperación?
Heredar directamente a AbstractLifecycle significa que se deben implementar todos sus métodos abstractos.
Por lo tanto, también necesitamos una implementación predeterminada, defaultLifeCycle, le permitimos heredar AbstractLifeCycle e implementar todos los métodos abstractos, pero no hace nada práctico, no hace nada. Simplemente permítanos la clase de implementación real heredar esta clase de implementación predeterminada y anular el método de interés.
Entonces, nació nuestro defaultLifecycle:
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 void, suspendinternal () arroja lifecycleException {// no hacer nada}/ * * @see abstractlifecycle#resume0 () */ @Override protegido void reume0 () lanza lifeCycleException {// no hacer nada " Proteged void destruye0 () lanza lifecycleException {// no hacer nada}} Para defaultLifeCycle, no hacer nada es su responsabilidad.
Entonces, a continuación, podemos escribir nuestra propia clase de implementación, heredar defaultLifecycle y reescribir esos métodos de interés del ciclo de vida.
Por ejemplo, tengo una clase que solo necesita hacer algunas tareas durante la inicialización, el inicio y la destrucción, por lo que puedo escribirla así:
import java.io.ioException; import java.net.serversocket; import java.net.socket; public class SocketServer extiende defaultLifeCycle {private ServerSocket Aceptor = null; Private Int Port = 9527; / * * @see defaultLifecycle#init0 () */ @Override void init0 () lanza lifecycleException {try {aceptor = new ServerSocket (puerto); } Catch (ioException e) {tirar nueva vida de lifeCycleException (e); }} / * * @see defaultLifecycle#start0 () * / @Override void start0 () lanza lifecycleException {socket socket = null; intente {socket = aceptor.accept (); // Haz algo con Socket} Catch (ioException e) {tirar nueva vida de lifeCleException (e); } Finalmente {if (Socket! = Null) {try {Socket.close (); } Catch (ioException e) {// tODO Auto Generated BLOCK E.PrintStackTRace (); }}}}} / * * @see DefaultLifecycle#destruye0 () * / @Override void destruye destruye0 () arroja lifecycleException {if (aceptor! = null) {try {aceptor.close (); } Catch (ioException e) {// tODO Auto Generated BLOCK E.PrintStackTRace (); }}}} En ServerSocket aquí, Init0 inicializa la escucha de socket, Start0 comienza a obtener la conexión de socket, destruye la escucha de socket.
Bajo este mecanismo de gestión del ciclo de vida, gestionaremos fácilmente los recursos, y no habrá apagado de recursos, y la arquitectura y la modularidad serán más claras.
fin
Hasta ahora, este artículo ha implementado un mecanismo de gestión del ciclo de vida simple y dado todos los códigos de implementación. Después de eso, todo el código fuente se colocará en GitHub. Preste atención a la actualización de este artículo.