Autofac时间驱动[tagged] scope:自动销毁单例作用域实现咨询
自动过期单例Scope的实现方案
是否存在原生支持的此类Scope?
标准依赖注入框架(如Spring、Guice)没有原生提供这种可配置定时销毁的单例Scope。部分第三方扩展包有类似实现,但如果不想依赖第三方,自定义实现是最灵活可靠的方案。你提到的pooled instances(池化实例)方案不匹配需求——池化是复用多实例,且缺少精准的定时过期销毁API,不适合单例场景。
正确实现方式
这类Scope的核心是带过期时间的单例缓存,需要实现以下逻辑:
- 维护实例缓存与对应过期时间戳
- 获取实例时懒检查过期状态,过期则销毁旧实例并创建新实例
- 定期主动清理过期实例(避免内存泄漏)
以Spring为例的自定义Scope实现
以下是一个可直接复用的实现示例:
import org.springframework.beans.factory.config.Scope; import org.springframework.stereotype.Component; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @Component public class ExpiringSingletonScope implements Scope { private final Map<String, Object> instanceCache = new HashMap<>(); private final Map<String, Long> expirationCache = new HashMap<>(); // 可从配置文件注入过期时间,此处示例为5分钟 private final long expireMillis = 300000; private final ScheduledExecutorService cleaner = Executors.newSingleThreadScheduledExecutor(); public ExpiringSingletonScope() { // 每分钟执行一次过期实例清理 cleaner.scheduleAtFixedRate(this::cleanExpiredInstances, 1, 1, TimeUnit.MINUTES); } @Override public Object get(String name, ObjectFactory<?> objectFactory) { synchronized (instanceCache) { if (isExpired(name)) { remove(name); } if (!instanceCache.containsKey(name)) { Object instance = objectFactory.getObject(); instanceCache.put(name, instance); expirationCache.put(name, System.currentTimeMillis() + expireMillis); } return instanceCache.get(name); } } @Override public Object remove(String name) { synchronized (instanceCache) { Object instance = instanceCache.remove(name); expirationCache.remove(name); // 销毁实例(如果实现了AutoCloseable) if (instance instanceof AutoCloseable) { try { ((AutoCloseable) instance).close(); } catch (Exception e) { // 按需处理销毁异常 } } return instance; } } private boolean isExpired(String name) { return expirationCache.containsKey(name) && System.currentTimeMillis() > expirationCache.get(name); } private void cleanExpiredInstances() { synchronized (instanceCache) { expirationCache.keySet().removeIf(name -> { if (isExpired(name)) { remove(name); return true; } return false; }); } } // 实现Scope接口的其他必填方法 @Override public String getConversationId() { return null; } @Override public void registerDestructionCallback(String name, Runnable callback) { // 可选:注册实例销毁时的回调逻辑 } @Override public Object resolveContextualObject(String key) { return null; } }
使用方式
- 将上述类注册到Spring容器(已加
@Component) - 在需要该Scope的Bean上标注:
@Scope("expiringSingleton") - 如需动态配置过期时间,可通过
@Value注入配置值替换硬编码的expireMillis
通用思路(非Spring场景)
无论使用哪种DI框架,核心逻辑一致:
- 用线程安全的容器存储实例和过期时间
- 获取实例时先校验过期状态,过期则销毁重建
- 启动定时任务定期扫描并清理过期实例
- 确保实例销毁时执行必要的资源释放逻辑(如关闭连接、释放内存)
内容的提问来源于stack exchange,提问作者Alexander.Furer
相关产品推荐
相关产品推荐

