You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何确保Guice注入的MyRepository在所有订阅者添加后才被使用?

可行解决方案

方案1:通过Guice Provider手动控制初始化顺序

先实现线程安全的MyRepository:

public class MyRepositoryImpl implements MyRepository {
    private final List<MyInterface> instances = new CopyOnWriteArrayList<>();

    @Override
    public void addInstance(MyInterface instance) {
        instances.add(instance);
    }

    @Override
    public List<MyInterface> getInstances() {
        return Collections.unmodifiableList(instances);
    }
}

在Guice模块中,先把MyRepository绑定为单例,然后在服务的Provider方法里先手动初始化所有MyInterface实现类(触发它们构造方法里的注册逻辑),再创建服务:

public class AppModule extends AbstractModule {
    @Override
    protected void configure() {
        bind(MyRepository.class).to(MyRepositoryImpl.class).in(Singleton.class);
    }

    @Provides
    @Singleton
    public MyService provideMyService(MyRepository repository) {
        // 先初始化所有订阅者,确保它们都注册到仓库
        new ObjectA(repository);
        new ObjectB(repository);
        // 这里添加所有需要的MyInterface实现类

        // 所有实例注册完成后,返回服务实例
        return new MyService(repository);
    }
}

这种方式能保证服务被注入时,仓库已经收集了所有订阅者,因为服务的创建依赖于所有实现类的初始化完成。

方案2:启动阶段提前初始化所有订阅者

将MyRepository绑定为单例后,在应用启动入口先获取所有MyInterface实现类的实例(触发构造方法的注册逻辑),再获取服务:

public class AppBootstrap {
    public static void main(String[] args) {
        Injector injector = Guice.createInjector(Stage.PRODUCTION, new AppModule());

        // 提前初始化所有订阅者,触发它们向仓库注册
        injector.getInstance(ObjectA.class);
        injector.getInstance(ObjectB.class);
        // 其他MyInterface实现类依次处理

        // 仓库完成所有注册后,安全获取服务使用
        MyService service = injector.getInstance(MyService.class);
        service.runBusinessLogic();
    }
}

注意使用Stage.PRODUCTION模式,Guice会保证单例的线程安全初始化,不会重复创建实例。

方案3:给仓库添加初始化完成钩子

扩展MyRepository,添加初始化完成的标记和等待逻辑,确保服务只能在初始化完成后访问仓库:

public class MyRepositoryImpl implements MyRepository {
    private final List<MyInterface> instances = new CopyOnWriteArrayList<>();
    private final CountDownLatch initLatch = new CountDownLatch(1);
    private boolean isInitialized = false;

    @Override
    public void addInstance(MyInterface instance) {
        if (isInitialized) {
            throw new IllegalStateException("仓库已完成初始化,无法再添加实例");
        }
        instances.add(instance);
    }

    @Override
    public List<MyInterface> getInstances() {
        try {
            initLatch.await(); // 阻塞直到初始化完成
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("等待仓库初始化被中断", e);
        }
        return Collections.unmodifiableList(instances);
    }

    // 对外暴露的初始化完成标记方法
    public void finishInitialization() {
        isInitialized = true;
        initLatch.countDown();
    }
}

在启动流程中,先初始化所有订阅者,再标记仓库完成初始化,最后启动服务:

public class AppBootstrap {
    public static void main(String[] args) {
        Injector injector = Guice.createInjector(new AppModule());
        MyRepository repository = injector.getInstance(MyRepository.class);

        // 初始化所有订阅者
        injector.getInstance(ObjectA.class);
        injector.getInstance(ObjectB.class);

        // 标记仓库初始化完成
        ((MyRepositoryImpl) repository).finishInitialization();

        // 服务现在可以安全使用仓库
        MyService service = injector.getInstance(MyService.class);
        service.processAllInstances();
    }
}

这个方案适合无法提前枚举所有MyInterface实现类的场景,只要在服务启动前调用finishInitialization即可。


内容的提问来源于stack exchange,提问作者user6342701

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 20:20:05