2011-01-08 2 views
17

Diciamo che ho un oggetto Closeable iniettato attraverso Guice con richiesta di applicazione:È possibile ripulire automaticamente le risorse alla fine dell'ambito in Guice?

@Provides @RequestScoped 
public MyCloseableResource providesMyCloseableResource(){ 
    return new MyCloseableResourceImpl(); 
} 

E 'possibile collegarsi ad Internet un metodo di pulizia che avrebbe chiamare automaticamente close() sulla mia risorsa, quando esiste la portata, senza ricorrere implementazione di ambito personalizzato?

Guardando la consuetudine scope implementation guide sul wiki Guice, dimostra che gli ambiti dovrebbero essere creati e puliti in questo modo:

/** 
* Runs {@code runnable} in batch scope. 
*/ 
public void scopeRunnable(Runnable runnable) { 
    scope.enter(); 
    try { 
    // explicitly seed some seed objects... 
    scope.seed(Key.get(SomeObject.class), someObject); 
    // create and access scoped objects 
    runnable.run(); 
    } finally { 
    scope.exit(); 
    } 
} 

Mi chiedo se non v'è modo di agganciare-up un po 'personalizzato clean-up codice nello finally degli ambiti incorporati (in particolare gli ambiti di sessione e richiesta).

Se non è possibile, potrebbero esserci problemi che potrebbero scoraggiare questo tipo di pulizia automatica?

Ho trovato modi per ottenere lo stesso effetto nei contenitori servlet di implementing a Filter per creare e pulire una risorsa per richiesta, che funziona benissimo ma sono curioso di sapere se è possibile con Guice puro.

risposta

5

Ho affrontato un problema simile me stesso e alla fine ho lanciato un'interfaccia Disposable che non offre nient'altro che un metodo public void dispose(). Lo trovo particolarmente utile per le classi che registrano gli ascoltatori da qualche parte e hanno bisogno di annullarli in un momento definito. Quello che avevo già era il mio AttributeHolderScope che I blogged about quindi non ripeterò quella parte qui. L'unica cosa che manca ora è il AbstractAttributeHolder che assomiglia a questo:

/** 
* An anstract base class for implementing the {@link AttributeHolder} 
* interface which has an implementation of the attribute related methods. 
* 
* @author Matthias Treydte <waldheinz at gmail.com> 
*/ 
public abstract class AbstractAttributeHolder 
     implements AttributeHolder, Disposable { 

    private final Object lock = new Object(); 
    private transient Map<Object, Object> attributes; 

    public AbstractAttributeHolder() { 
     this.attributes = new HashMap<Object, Object>(); 
    } 

    public void replaceAttributes(Map<Object, Object> newAttr) { 
     synchronized (getAttributeLock()){ 
      this.attributes = newAttr; 
     } 
    } 

    @Override 
    public Object getAttributeLock() { 
     return this.lock; 
    } 

    @Override 
    public final void putAttribute(Object key, Object value) { 
     synchronized (getAttributeLock()) { 
      attributes.put(key, value); 
     } 
    } 

    @Override 
    public final boolean hasAttribute(Object key) { 
     synchronized (getAttributeLock()) { 
      return attributes.containsKey(key); 
     } 
    } 

    @Override 
    public final Object getAttribute(Object key) { 
     synchronized (getAttributeLock()) { 
      return attributes.get(key); 
     } 
    } 

    @Override 
    public final Set<Object> getAttributes() { 
     synchronized (getAttributeLock()) { 
      return Collections.unmodifiableSet(
        new HashSet<Object>(this.attributes.values())); 
     } 
    } 

    @Override 
    public void dispose() { 
     synchronized (this.getAttributeLock()) { 
      for (Object o : this.attributes.values()) { 
       if (o instanceof Disposable) { 
        final Disposable d = (Disposable) o; 
        d.dispose(); 
       } 
      } 

      this.attributes.clear(); 
     } 
    } 
} 

Questa classe stessa implementa Disposable ambiti in modo da poter avere nidificate e quando si deve smaltire un ambito esterno, tutti gli ambiti annidati e, cosa ancora più importante, tutti i istanze iniettate che implementano Disposable vengono ripulite. E per rispondere con precisione alla tua domanda: non penso che ciò sia possibile con le implementazioni Scope fornite da Guice stessa, ma può essere fatto. Ogni volta che guardo questo codice mi chiedo se questo non può essere fatto in un modo più conciso, ma poi funziona magnificamente (almeno per me).

+0

Un'implementazione di ambito estendibile, ottima idea! Quindi, per usare questo con scope di richiesta, creo 'MyRequestScope' estendendo la classe scope dal blog, collegandola allo stesso punto del predefinito' RequestScope' (la parte difficile), esegui 'scope.enter()' con ' AbstractAttributeHolder' e assicurati di chiamare 'dispose()' nella fine (o nel 'exit()' di 'MyRequestScope')? Se hai un bel modo di integrare questo potresti condividerlo (il codice e/o le tecniche) per favore? – rodion

+0

Per quanto riguarda il codice relativo alla sincronizzazione, sembra non necessario perché 'AttributeHolder' è sempre accessibile da' ThreadLocal', quindi un'istanza univoca per thread. Mi sto perdendo qualcosa? – rodion

+0

1) Non lo uso in un ambiente servlet, quindi non sono sicuro di come farlo correttamente. – Waldheinz