我有以下情况:
public class User {
@Inject
private MusicInterface movie;
}
public interface MusicInterface {
public void getTitle();
}
并且有 Guice 配置类:
public class Module extends AbstractModule {
@Override
protected void configure() {
bind(MusicInterface.class).annotatedWith(Names.named("rock")).to(RockMusic.class);
bind(MusicInterface.class).annotatedWith(Names.named("pop")).to(PopMusic.class);
bind(User.class).annotatedWith(Names.named("user1").to(User.class);
bind(User.class).annotatedWith(Names.named("user2").to(User.class);
}
}
我的问题是: 如何将我想要的音乐绑定(bind)注入(inject)到用户类中?
例如:
在我的 main 中,我想获得带有名为 rock 的注入(inject)类的 User1:
Injector injector = Guice.createInjector(new Module());
User user1 = injector.getInstance(Key.get(User.class,Names.named("user1")));
假设 user1 具有属性 RockMusic.class,稍后我想让 user2 获得流行音乐:
User user2 = injector.getInstance(Key.get(User.class,Names.named("user2")));
这个类将具有属性 PopMusic.class。
我该怎么做?
我知道我可以在 User 类中使用注释 @Named(...),但这不是我的情况的解决方案。
最佳答案
听起来您想要做的是根据用户的注释绑定(bind)不同种类的音乐。这也称为 the Robot Legs problem ,除非您可以将“腿”替换为“用户”,将“脚”替换为“音乐”。这可以使用 Private Modules 来实现。在 Guice 中,但您可能会发现创建 UserFactory 更容易。我将向您展示两种方法。
首先,Private Module方式。私有(private)模块向外界隐藏所有绑定(bind),因此您可以公开某些模块而不会与其他模块发生冲突。
public class MyModule extends AbstractModule {
@Override protected void configure() {
install(privateModuleFor("user1", RockMusic.class));
install(privateModuleFor("user2", PopMusic.class));
}
private static Module privateModuleFor(
final String userName, final Class<? extends MusicInterface> musicClass) {
return new PrivateModule() {
@Override protected void configure() {
// Bind the annotated user.
bind(User.class).annotatedWith(Names.named(userName)).to(User.class);
// Now bind the music class as if it's the only music class ever.
bind(MusicInterface.class).to(musicClass);
// The above two bindings are hidden, and available only in this module,
// so Guice doesn't complain about two different competing
// MusicInterfaces. In order to get access to the User binding
// outside the module, expose it.
expose(User.class).annotatedWith(Names.named(userName));
}
};
}
}
现在您可以请求 @Named("user1") User
获得喜欢摇滚音乐的用户。当然,您不必像我使用该方法那样组织它:如果您愿意,您仍然可以将 MusicInterface 的类型绑定(bind)到名称,然后将无注释的 MusicInterface 绑定(bind)到 Key.get(MusicInterface.class, yourMusicTypeHere)
在您的 PrivateModule 中,但除非您在其他地方需要指定的 MusicInterfaces,否则您可以跳过该步骤。
另一种方法是跳过使用 Guice 进行此绑定(bind)。 Guice 是一个很好的解决方案,但对于一些复杂的绑定(bind)情况,设置起来可能会比较麻烦。您的替代方案是创建一个轻量级 UserFactory 来为您选择正确的音乐类型。 ( ImmutableMap 来自 Guava 。)
public class UserFactory {
private Map<String, Class<? extends MusicInterface>> musicMap =
ImmutableMap.builder()
.put("user1", RockMusic.class) // You could also put instances here
.put("user2", PopMusic.class) // and skip using Guice entirely!
.build();
// Never inject Injector unless you don't know what you need until runtime,
// which is exactly what is happening here.
@Inject private Injector injector;
@Inject private Provider<Dependency> someOtherUserDependency;
public User createUser(String musicType) {
Class<? extends MusicInterface> clazz = musicMap.get(musicType);
return new User(injector.getInstance(clazz), someOtherUserDependency.get());
}
}
现在您的用户将可以通过注入(inject) UserFactory
来使用并调用userFactory.create()
。当然,也许您的用户需要十几个其他注入(inject)的依赖项。在这种情况下,第一个选项看起来不错,或者您可以调查 assisted injection 。所有这些都是可行的选项,因此您需要考虑哪一个是适合您的情况的灵 active 和可读性的正确组合。
希望有帮助!
关于java - 如何配置 Guice,使其注入(inject)到我想要的绑定(bind)类中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13807747/