Guice@为一个依赖实例提供两次单例



我想知道如何将单例绑定到提供程序中的参数。

即:

@Singleton
public class RunButtonController{
    @Inject
    public RunButtonController(EventBus eventbus){ ... }
    public JComponent getView(){
        return view;
    }
    ...
}
public class UncaughtExceptionController{
    @Inject
    public UncaughtExceptionController(
        EventBus eventBus, ..., 
        @Named(DefaultExceptionViewKey) JComponent defaultView)
    { ... }
    ...
}
public class GUIController{
    //another consumer of RunButtonController, arguably the "main" consumer. 
    @inject
    public GUIController(RunButtonController runButtonController,
                         UncaughtExceptionController uncaughtExceptionController, ...)
    { ... }
    ...
}
public class Bootstrapper{
    public static void main(String[] args){
        Injector injector = Guice.createInjector(new OptipModule());
        GUIController controller = injector.getInstance(GUIController.class);
    }
    private static class OptipModule extends AbstractModule{
        @Override
        protected void configure() {
            bind(EventBus.class).toInstance(new EventBus("OPTIPGlobalEventBus"));
            bind(JFrame.class).to(GUIView.class);
        }
        @Provides @Named(DefaultExceptionViewKey)
        public JComponent getFrom(RunButtonController runButtonController){
            return runButtonController.getView();
        }
    }
}

在我的RunButtonController构造函数上放置一个断点,我可以看到它总是被实例化两次。我希望它只实例化一次,并且defaultExceptionViewProvider == runButtonController为CCD_ 3。

我使用过温莎城堡相当广泛,但那是我唯一使用过的国际奥委会集装箱,所以我是新手。我看到到处都是访问者行为的残余,guice的文档非常清楚地表明,类的定义行为(即,实例一次,使用此实例,使用此工厂,…)不会在为其配置的模块之外持续存在。我想说的是,我看到它写道,当你使用@Provides时,guice会为你创建一个子模块,所以我需要做的大概是告诉这个child@Providers生成的模块,‘嘿,这个类是一个singleton,我正在解决它,所以它就在这里!不要用你自己的

我认为我对这个框架的理解是错误的。我一直在破坏注释并进行调试,但也许我真正需要做的是花几个小时阅读一个好的教程,不幸的是我找不到。JavaDoc有一些例子,网页会发布它们,但它们给你的上下文很少,所以,在@Assisted上读了三遍的文章后,我仍然不明白(也许这就是我应该使用的?)对于那些指向一个特别详细的博主和页面上的指导条目的人来说,这是一个加分项。

沿着这些思路,我非常离题,我想知道我试图把这个"嘿,你的默认通知区域是其他人的视图"推到我的国际奥委会容器里会有什么后果。这可能是域逻辑吗?我真的不想让UnhandledExceptionController知道它的视图是由RunButtonController提供的,同样,我也不希望RunButtonController知道它的观点被用于除被冲压到视图树之外的任何事情。

感谢阅读!

正如所发布的,您的代码看起来应该可以工作也就是说,有一些注意事项可能会导致单身汉共存。仔细检查每个构造函数调用的堆栈跟踪。

  • 这可能是显而易见的,但您可以在Guice的控制之外创建任何数量的实例,而Guice无法知道这些实例的存在。仔细检查代码中是否没有任何内容手动调用RunButtonController构造函数。

  • Singleton行为是在任何给定的注入器中强制执行的。如果您的应用程序中有两个或多个注入器,它们可以各自创建自己的RunButtonController实例。但是,在父注入器中声明的singleton对任何子注入器都是可见的。

  • 辛格尔顿通过键工作。如果要删除@Singleton注释并添加以下内容:

    bind(RunButtonController.class)
        .annotatedWith(Names.named("Foo"))
        .asEagerSingleton()
    

    然后注入RunButtonController每次都会得到一个新实例,但注入@Named("Foo") RunButtonController每次都会获得一个单独的单例实例,该实例每次都会返回相同的实例。这可能不适用于您,因为@Singleton本身就在类上,但它以前也咬过其他类。

  • 您似乎不依赖于继承,但请记住,singleton注释不会从超类继承到子类。

附带说明:@Provides方法不通过子注入器工作,但私有模块可以(在文档中被间接称为"父注入器")。在内部,确实有一个单独的内部模块负责调用这些提供程序方法,但这并不重要——singleton在模块之间共享。

关于您关于共享视图的题外话:通过注入@Named(DefaultExceptionViewKey) JComponent而不是RunButtonController,您已经做得相当好了,但如果您想更不了解实现,您可以创建一个ExceptionHandlerComponent接口并编写相应的代码。

最新更新