2

我目前正在尝试在一个小型应用程序中使用 Google Guice-3.0。

运行此应用程序时,系统会提示用户输入其姓名和密码。由于此信息直到运行时才知道,所以我使用它AssistedInject来实现我的User实例化。

这就是 myUserFactory进来的地方。它提供了一个Userwith 方法

public User create(@Assisted("Username") String username, 
                   @Assisted("Password") String password);

User课程在程序开始时(在用户输入之后)通过

User user = getInjector().getInstance(UserFactory.class).create(username, password);

我想在应用程序的整个生命周期内使用这个实例。我已经将范围设置为@Singleton.

问题是,但是,我只得到错误。Guice 抱怨我在调用时没有传递任何变量

User user = getInjector().getInstance( User.class );

如果我bind( User.class );configure方法中添加 a ,则会发生错误,即注释没有声明@Assisted(因为您可以将注释放在参数前面以唯一标识它们 - Guice 可能认为它是其中之一并要求设置依赖项(喜欢

bind( String.class ).annotatedWith( Assisted.class ).toInstance( username );

但这不是一件可行的事情(也许它会通过静态引用但为什么要使用 Guice?

这是您可以编译的示例。注释的代码会导致错误。特别是最后两行对我来说很烦人。

public class KSKB {

    @Singleton
    public static class User {

        public final String name;

        @Inject
        public User(@Assisted("Username") String username) {
            this.name = username;
        }

        public static interface Factory {
            public User create(@Assisted("Username") String username);
        }
    }

    public static void main(String... args) {
        Injector injector = Guice.createInjector(new AbstractModule() {

            @Override
            protected void configure() {
                install(new FactoryModuleBuilder().build(User.Factory.class));
                // bind( User.class );
            }

        });
        User user = injector.getInstance(User.Factory.class).create("Guice");
        System.out.println(user.name);

        // user = injector.getInstance( User.class ); // doesn't work - throws Exception!!
        // System.out.println( user.name );
    }
}
4

2 回答 2

3

我不认为能得到你想要的,因为你想破坏 Guice。

Guice 希望自己管理实例及其创建。即使在 Guice 的支持下,您也可以使用Provider和自定义工厂来自己创建对象。Assisted但是您不能将这些实例反馈回 Guice。这意味着,您不能告诉 Guice 使用特定对象作为单例实例。1

可能且简单的解决方案:

  • 在创建注入器之前确定用户名,并bindConstant()在模块中使用绑定用户名。在 中使用适当的对应物User。然后你可以标记User@SingletonGuice 会尊重它。

  • 用户bind(User.class).toInstance(myUser);。这类似于第一个提议,因为必须在 Guice 启动和运行之前获取所需的用户名。

  • 不要注入User一个中间对象UserHolder(或UserManager),它是单例。该对象具有存储实际用户和获取它的方法。您的初始化代码将获取该持有人(当时为空)并将创建User的持有人放入持有人。您的应用程序的其他部分也将注入UserHolder.


1至少没有肮脏的把戏。

于 2012-08-07T08:44:03.937 回答
0

辅助注射的输出不是注射——它是自动接线的工厂(很遗憾,该设施的名字很可怕)。

AssistedInject 产生的是一个工厂——这个工厂可以是单例的。但它是一个工厂,所以它的工作是创建对象,比如 User 对象。Factory 的内部没有设置为让它创建单例值对象。一般来说,值对象不是单例对象——你在这里使用一个作为“上下文”而不是数据,所以你有一个特殊情况。

此外,您的情况更加特殊,因为您希望在 guice 甚至运行之前预先验证数据库中的数据。这个用户完全是上下文,而不是数据,所以不要使用工厂来创建它。手动创建它,如果您需要在 guice 绑定系统的其他地方使用它,然后在 Guice 之外创建它,并将其作为 DatabaseCredentials 对象或类似对象传递到模块中。

为了适当地帮助您,我们需要看到一个更大的设计概念,但我的感觉是,您并没有清楚地考虑协作者/服务、值类型、上下文/配置等之间的区别,并且混淆主要是来是因为“用户”这个词在这里超载了。是的,它是一个“用户”,但数据库用户与系统中的其他用户不同——即使它在结构上相同,也意味着不同的东西,具有不同的生命周期等。

于 2012-08-20T14:15:25.827 回答