是否可以在 Guice 中范围结束时自动清理资源?

2022-09-02 14:05:57

假设我使用请求范围通过 Guice 注入了一个对象:Closeable

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

是否可以挂接一个清理方法,该方法将在作用域存在时自动调用我的资源,而无需诉诸自定义作用域实现?close()

查看 Guice wiki 上的自定义作用域实现指南,它表明应按如下方式创建和清理作用域:

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

我想知道是否有办法在内置范围(特别是会话和请求范围)中挂接一些自定义清理代码。finally

如果不可能,是否存在阻止这种自动清理的问题?

我已经找到了在 servlet 容器中实现相同效果的方法,方法是实现一个 Filter 来为每个请求创建和清理一个资源,这效果很好,但我很好奇它是否可能使用纯 Guice。


答案 1

我自己也遇到了类似的问题,最终推出了一个界面,除了一种方法之外什么都没有。我发现这对于在某个地方注册侦听器并需要在定义时间取消注册它们的类特别有价值。我已经拥有的是我写博客的,所以我不会在这里重复那部分。现在唯一缺少的是看起来像这样的:Disposablepublic void dispose()AttributeHolderScopeAbstractAttributeHolder

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

此类本身实现,因此您可以拥有嵌套作用域,并且在释放外部作用域时,将清理所有嵌套作用域,更重要的是,所有实现的注入实例。为了准确地回答你的问题:我不认为这在Guice本身提供的实现中是可能的,但它是可以做到的。每次我看这段代码时,我都会问自己,这是否可以以更简洁的方式完成,但它可以很好地工作(至少对我来说)。DisposableDisposableScope


答案 2

推荐