java - provides - guice requestscoped
¿Es posible limpiar automáticamente los recursos al final del alcance en Guice? (1)
Digamos que tengo un objeto Closeable
inyectado a través de Guice utilizando el alcance de solicitud:
@Provides @RequestScoped
public MyCloseableResource providesMyCloseableResource(){
return new MyCloseableResourceImpl();
}
¿Es posible conectar un método de limpieza que llame automáticamente a close()
en mi recurso cuando exista el alcance, sin recurrir a la implementación del alcance personalizado?
Mirando la guía de implementación de alcance personalizado en la wiki de Guice, muestra que los ámbitos deben crearse y limpiarse así:
/**
* 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 alguna manera de conectar algún código de limpieza personalizado en el final de los ámbitos integrados (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 los contenedores de servlets al implementar un Filtro para crear y limpiar un recurso por solicitud, que funciona muy bien, pero tengo curiosidad si es posible con Guice puro.
Yo mismo me enfrenté a un problema similar y finalmente introduje una interfaz Disposable
que no ofrece más que un método de public void dispose()
. Considero que esto es especialmente valioso para las clases que registran oyentes en algún lugar y necesitan anular su registro en un momento definido. Lo que ya tenía era mi AttributeHolderScope
que escribí el blog, así que no repetiré esa parte aquí. Lo único que falta ahora es AbstractAttributeHolder
que se ve así:
/**
* 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 implementa el Disposable
para que pueda tener ámbitos anidados y cuando se desecha un alcance externo, se eliminan todos los ámbitos anidados y, lo que es más importante, todas las instancias inyectadas que implementan el Disposable
. Y para responder con precisión a su pregunta: no creo que esto sea posible con las implementaciones de Scope
provistas por Guice en sí, 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 a la perfección (al menos para mí).