2012-01-23 12 views
17

Attualmente sto sviluppando un'applicazione in cui devo gestire lo stato di diversi servizi e fermarli/avviarli in base ad alcuni eventi. Il problema è che, come dichiarato nei documenti, il servizio di Guava è unidirezionale, il che significa che, una volta arrestato, non può essere riavviato.Servizio riavviabile utilizzando Guava

Dal momento che ho bisogno di aggirare questo problema in qualche modo, mi trovo di fronte a un paio di alternative, che vorrei mettere in discussione (soprattutto perché potrebbero esserci degli svantaggi per cui non sono a conoscenza del giusto adesso).

La prima soluzione ovvia a questo problema consiste nell'istanziare un nuovo servizio quando è necessario "riavviarlo". Funziona, ma nella mia attuale architettura complicherebbe un po 'le cose: attualmente sto installando tutti i servizi, e basandomi sugli eventi di un EventBus, iniziando o fermandoli se necessario. La classe che chiama i metodi start e stop salva solo un riferimento a una mappa di servizi e chiama il metodo giusto su tali istanze in base all'evento ricevuto. Se ho bisogno di istanziare un nuovo oggetto in risposta ad un evento, dovrò rinunciare ad alcuni dei disaccoppiamenti che ho attualmente (possibilmente mantenendo la classe di ogni tipo di servizio e invocando il costruttore usando la riflessione).

Un'altra possibilità è implementare l'interfaccia di servizio come servizio RestartableThreaded (o qualcosa del genere). Se ho seguito questa strada, il mio metodo start() potrebbe creare un altro Thread come se fosse la prima volta e ripristinare gli stati.

C'è qualche chiaro svantaggio per il secondo approccio? Temo che potrebbe mancare qualche ovvio inconveniente qui (oltre a dover codificare qualcosa di un po 'più complicato), specialmente per quanto riguarda la gestione dei thread.

risposta

3

Consiglierei il vostro primo approccio, ma ci sono modi migliori per farlo rispetto alla riflessione. Utilizzare l'iniezione di dipendenza, o possibilmente passare intorno agli oggetti Supplier<Service> invece di usare serviceClass.newInstance(), è probabilmente il modo per andare qui.

+0

Grazie per la risposta, questa sembra la strada da percorrere. Se prendo il percorso di DI, darò un'occhiata migliore agli ambiti di Guice come suggerito da Craig, ma i fornitori sembrano promettenti. Sfortunatamente riprenderò le mie mani su questo compito tra un paio di giorni, aggiornerò la mia domanda con ulteriori dettagli/opzioni. – pcalcao

+0

Ho avuto un caso d'uso simile e ho adottato un approccio ibrido. Ho usato una cache a elemento singolo piuttosto che un fornitore, in quanto mi ha permesso di cancellare/invalidare la voce quando è stata interrotta. Ma ho messo la mia cache in una classe che implementava il servizio (e per lo più solo delegato al servizio memorizzato nella cache) solo così potevo avere l'API. – Ray

1

Considerare l'utilizzo degli ambiti di Guice.

1

Lo stesso problema viene monitorato in questo github: https://github.com/google/guava/issues/418

ho una proposta di modifica qui: https://github.com/okigan/guava/commit/8f51b155f9ce5c60236b9a9bfdc6ca5f8bf5e51d

l'essenza di esso è di aggiungere un reset() per AbstractService che permette la transizione da TERMINATED indietro NOVITÀ:

public final void reset() { 
    lock.lock(); 
    try { 
     switch (snapshot.state) { 
      case TERMINATED: 
      case FAILED: 
       snapshot = new StateSnapshot(State.NEW); 
       break; 
      default: 
       throw new AssertionError("Unexpected state: " + snapshot.state); 
     } 
    } catch (Throwable resetFailure) { 
     notifyFailed(resetFailure); 
    } finally { 
     lock.unlock(); 
     executeListeners(); 
    } 
}