2011-01-08 18 views
17

Digamos que tengo un objeto Closeable inyectado a través de Guice usando solicitud alcance:¿Es posible limpiar automáticamente los recursos al final del alcance en Guice?

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

¿Es posible conectar en marcha un método de limpieza que se llamará automáticamente close() en mi recurso cuando existe el alcance, sin recurrir a la implementación de alcance personalizado?

En cuanto a la costumbre scope implementation guide en el wiki de Guice, muestra que alcances deben ser creados y limpiados de esta manera:

/** 
* 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(); 
    } 
} 

Me pregunto si hay manera de conectar en marcha alguna costumbre limpieza código en el finally de los ámbitos incorporados (especialmente los ámbitos de sesión y solicitud).

Si no es posible, ¿podría haber problemas que desalienten este tipo de limpieza automática?

He encontrado formas de lograr el mismo efecto en contenedores servlet por implementing a Filter para crear y limpiar un recurso por solicitud, que funciona muy bien, pero tengo curiosidad si es posible con Guice puro.

Respuesta

5

Me enfrenté a un problema similar y finalmente rodé una interfaz Disposable que ofrece nada más que un método public void dispose(). Encuentro esto especialmente valioso para las clases que registran oyentes en algún lugar y necesitan cancelar el registro en un momento definido. Lo que ya tenía era mi AttributeHolderScope que I blogged about así que no repetiré esa parte aquí. Lo único que falta ahora es el AbstractAttributeHolder que se parece a esto:

/** 
* 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(); 
     } 
    } 
} 

Esta clase misma implementa Disposable alcances para que pueda tener anidados y cuando disponga de un ámbito exterior, todos los ámbitos anidados y, más importante, todo las instancias inyectadas que implementan Disposable se limpian. Y para responder con precisión a su pregunta: no creo que esto sea posible con las implementaciones Scope proporcionadas por Guice, pero se puede hacer. Cada vez que miro este código me pregunto si esto no se puede hacer de una manera más concisa, pero luego funciona maravillosamente (al menos para mí).

+0

Implementación de alcance extensible, muy buena idea! Entonces, para usar esto con el alcance de la solicitud, crearía 'MyRequestScope' extendiendo su clase de alcance desde el blog, lo conectaría al mismo lugar que el' RequestScope' predeterminado (la parte difícil), haré 'scope.enter()' con ' AbstractAttributeHolder' y asegúrate de llamar 'dispose()' al final (o en 'exit()' de 'MyRequestScope') Si tiene una buena forma de integrar esto, ¿podría compartirlo (el código y/o las técnicas), por favor? – rodion

+0

En cuanto al código relacionado con la sincronización, parece innecesario porque 'AttributeHolder' siempre se accede desde' ThreadLocal' por lo tanto, una instancia única por subproceso. ¿Me estoy perdiendo de algo? – rodion

+0

1) No uso esto en un entorno Servlet, por lo que no estoy seguro de cómo hacerlo correctamente. – Waldheinz

Cuestiones relacionadas