Java "的输出;“协助”;工厂应该是@Singleton

Java "的输出;“协助”;工厂应该是@Singleton,java,guice,inject,Java,Guice,Inject,我目前正在尝试在一个小应用程序中使用GoogleGuice-3.0 运行此应用程序时,系统会提示用户输入其姓名和密码。由于直到运行时才知道这些信息,所以我使用AssistedInject来实现User实例化 这就是我的UserFactory的用武之地。它为用户提供了该方法 public User create(@Assisted("Username") String username, @Assisted("Password") String passwo

我目前正在尝试在一个小应用程序中使用GoogleGuice-3.0

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

这就是我的
UserFactory
的用武之地。它为
用户
提供了该方法

public User create(@Assisted("Username") String username, 
                   @Assisted("Password") String password);
User
类在程序开始时(用户输入后)通过

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

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

User user = getInjector().getInstance( User.class );
如果我添加一个
bind(User.class)
configure
方法中,出现一个错误,即没有对注释
@Assisted
进行声明(因为您可以将注释放在参数前面以唯一标识它们-Guice可能认为它是其中之一,并要求设置依赖项(如

但这不是一件可以工作的事情(也许它可以通过静态引用工作,但是为什么要使用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 );
    }
}

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

Guice希望自己管理实例及其创建。您可以使用
提供程序
和自定义工厂(如
辅助
工具)自行创建对象,即使有Guice的支持也是如此。但您不能将这些实例反馈回Guice。这意味着,您不能告诉Guice使用特定对象作为singleton i第1节

可能和简单的解决方案:

  • 在创建注入器之前确定用户名,并在模块中使用
    bindcontent()
    绑定用户名。在
    user
    中使用相应的对应项。然后您可以使用
    @Singleton
    标记
    user
    ,Guice将予以认可

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

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



1至少没有肮脏的把戏。

辅助注射的输出不是注射,而是自动接线的工厂(不幸的是,该工厂的名称很糟糕)

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

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


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

Sry,Stackoverflow的新用户…我想补充几个问题:由于用户有密码,我必须使用此密码启动UserModule构造函数,然后将其存储在字段中,然后在配置方法中引用它。例如:
final String username;final char[]password;public UserModule(String username,char[]password){this.username=username;this.password=password;}@Override public void configure(){bind(User.class).toInstance(新用户(用户名,密码));}
另一个问题:为什么我不能将列表绑定到LinkedList或其他东西?在Java的普通类中:[关于“SO的新内容”:没问题,欢迎光临。但您必须了解SO不是聊天网站。这意味着其他用户也希望找到与他们的问题相关的问题。只有当不同的问题被划分为不同的问题时,这才可能。尤其是“列表”这个问题在这里被问了好几次。关于第一项:重要的是
bind(User.class).toInstance(…)
你做得对的事情。用户名和密码如何进入那个位置并不重要。但它应该会起作用。谢谢你的回答。我将分开我的问题,但我还有另一个问题:正如你所建议的,我在UserModule的构造函数中传递了这些参数,但有一个简单的问题。我不想排除主机和端口可能不同,因此我已将常量host和port绑定到@Named(“host”)。因此我的用户如下所示:
User(@Named(“host”)String host,@Named(“port”)int port,String username,String password)
如何将
User.class
绑定到此实例而不指定主机和端口?我可以
bind( String.class ).annotatedWith( Assisted.class ).toInstance( username );
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 );
    }
}