Guice @Provides具有两个单例的依赖实例

时间:2013-08-14 18:37:38

标签: java annotations singleton inversion-of-control 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 == runButtonControllertrue

我已经相当广泛地使用了Castle Windsor,但那是我用过的唯一一个IOC容器,所以我是新来的guice。我在整个地方都看到了访问者行为的残余,而guice的文档清楚地表明,类的定义行为(即实例一次,使用此实例,使用此工厂,......)不会持续存在它配置的模块。我想说我写的是当你使用@Provides时,guice会为你创建一个子模块,所以我需要做的就是告诉这个孩子@提供生成的模块'嘿,这个类是单身,我正在解决它,所以在这里!不要使用你自己的!'

我认为我以错误的方式处理这个框架。我一直在粉碎注释和调试,但也许我真正需要做的是花几个小时阅读一个很好的教程,不幸的是我找不到一个。 JavaDoc有示例,网页发布它们,但是它们给你很少的上下文,所以,在阅读了@Assisted 三次的文章之后,我仍然不理解它(perhalps那是我的意思)应该使用?)奖励积分指向一个特别详细的博主和他的页面上的guice条目的方向。

沿着这些方向,并且极度离题,我想知道我试图推动这个“嘿你的默认通知区域是其他人看到'进入我的IOC容器的后果是什么。这可能是域逻辑吗?我真的不希望UnhandledExceptionController知道它的视图是由RunButtonController提供的,同样我也不希望RunButtonController知道它的视图被用于其他任何其他内容而不是被压印到视图树上。

感谢阅读!

1 个答案:

答案 0 :(得分:2)

发布时,看起来您的代码应该可以正常工作。也就是说,有一些警告可能导致单身人士共存。仔细检查每个构造函数调用的堆栈跟踪。

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

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

  • 单身人士通过密钥工作。如果您要删除@Singleton注释并添加此项:

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

    然后注入RunButtonController每次都会获得一个新实例,但是注入@Named("Foo") RunButtonController会得到一个单独的单例实例,每次都会返回相同的实例。这可能不适用于你,因为@Singleton在班级本身,但它之前已经咬过其他人。

  • 您似乎不依赖继承,但请记住singleton annotations don't inherit from superclass to subclass

旁注:@Provides方法不能通过子注入器工作,但私有模块可以(提到“父注射器”in the documentation)。在内部,separate internal module负责调用这些提供者方法,但这并不重要 - 单个模块之间共享。

关于分享视图的离题:通过注入@Named(DefaultExceptionViewKey) JComponent代替RunButtonController,您已经做得相当不错,但如果您想要更加与实现无关,那么您可以创建一个{{ 1}}接口和代码。