我目前正在尝试在小型应用程序中使用Google Guice-3.0。
运行此应用程序时,系统会提示用户输入他的姓名和密码。由于在运行时之前不知道此信息,因此我使用AssistedInject
来实现我的User
实例化。
我的UserFactory
就在这里。它提供User
方法
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
,则会发生错误,即注释@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 );
}
}
答案 0 :(得分:3)
我不认为可以得到你想要的东西,因为你想破坏Guice。
Guice希望自己管理实例及其创建。您可以使用Provider
和自定义工厂(如Assisted
)自行创建对象 - 即使有Guice的支持。但是你无法将这些实例反馈给Guice。这意味着,您不能告诉Guice使用特定对象作为单例实例。 1
可行且简单的解决方案:
在创建注入器之前确定用户名,并在模块中使用bindConstant()
来绑定用户名。使用User
中的相应对应项。然后,您可以使用User
标记@Singleton
,而Guice会尊重它。
用户bind(User.class).toInstance(myUser);
。这与第一个提案类似,因为必须在Guice启动并运行之前获取所需的用户名。
不要注入User
,而是注入单身的中间对象UserHolder
(或UserManager
)。该对象具有存储实际用户并获取它的方法。您的初始化代码将获取该持有者(当时为空)并将创建的User
放入持有者。您的应用程序的其他部分也将注入UserHolder
。
1 至少没有脏技巧。
答案 1 :(得分:0)
辅助注射的输出不是注射 - 它是自动连接的工厂(该设施的名字很可怕,令人遗憾)。
AssistedInject产生的是一个工厂 - 该工厂可以是单件。但它是一个工厂,所以它的工作是创建对象,比如User对象。 Factory的内部设置不是为了让它创建Singleton值对象。一般来说,值对象不是单例对象 - 你在这里使用的是“上下文”而不是数据,所以你有一个特例。
此外,您的情况更加特殊,因为您希望在guice运行之前预先验证数据库中的数据。此用户完全是上下文,而不是数据,因此请勿使用工厂来创建它。手动创建它,如果你需要在guice绑定系统的其他地方使用它,那么在Guice外部创建它,并将它作为DatabaseCredentials对象或类似物传递给模块。
为了正确地帮助你,我们需要看到一个更大的设计概念,但我的感觉是,你没有清楚地思考协作者/服务,价值类型,背景/配置等之间的区别,以及混淆很大程度上是因为“用户”这个词在这里超载了。是的,它是一个“用户”,但数据库用户与系统中的其他用户不是同一类用户 - 即使它在结构上相同,它意味着不同的东西,具有不同的生命周期等等。