使用 Guice 嵌套注入
Use Guice nested injects
我对 Guice 比较陌生,有些事情仍然让我很难过。
我的具体问题是,您如何处理 Guice 中的嵌套注入。
示例:
Class A 通过 @Inject
使用 Class B,Class B 使用 Class C.
明确:
我绑定到提供商的模块。
public class ModuleBinder extends AbstractModule {
@Override
protected void configure() {
bind(DatabaseControllerInterface.class)
.toProvider(DatabaseControllerProvider.class).asEagerSingleton();
bind(AnalyzerInterface.class)
.toProvider(AnalyzerProvider.class).asEagerSingleton();
bind(SystemAdministrationInterface.class)
.toProvider(SystemAdministrationProvider.class).asEagerSingleton();
bind(LogInServiceInterface.class)
.toProvider(LogInServiceProvider.class);
}
}
DatabaseControllerProvider:
public class DatabaseControllerProvider implements Provider<DatabaseControllerInterface> {
@Override
public DatabaseControllerInterface get() {
return new DatabaseControllerImpl();
}
}
LogInServiceProvider:
public class LogInServiceProvider implements Provider<LogInServiceInterface> {
@Override
public LogInServiceInterface get() {
return new LogInServiceImpl();
}
}
最后,LogInService 使用:
public class LogInServiceImpl implements LogInServiceInterface{
@Inject
private DatabaseControllerProvider databaseControllerProvider;
private final DatabaseControllerInterface databaseController;
public LogInServiceImpl() {
this.databaseController = databaseControllerProvider.get();
}
@Override
public User register(final String mail, final String userName, final String password) {
databaseController.registerUser(userName, mail, password, UserRole.ADMIN);
}
}
那么电话是:
public class Test() {
public static test() {
final Injector injector = Guice.createInjector(new ModuleBinder());
logInService = injector.getInstance(LogInServiceInterface.class);
logInService.registerUser("test", "test", "test");
}
}
我知道你们中的大多数人都会厌倦那些代码,但是嘿,我是 Guice 的初学者,所以请对我温柔一些。
我想使用构造函数注入,我已经意识到可以考虑字段注入"evil"。您知道如何通过保留提供者(我需要他们)来实现它吗?
使用示例中的注入在 "second" 级别上没有任何作用,LogInServiceImpl
中的 DatabaseControllerImpl
是 null
。
我是不是配置有误?我是否误解了 Provides and/or 模块的用法?
我希望有人能够并且愿意帮助我。如果您需要更多信息,post 评论。
谨致问候,
约瑟夫背囊
您的直接回答:您在不支持字段注入的提供程序中调用 new T();
。
首先,一个真正节省时间的方法:不要保留您的显式提供程序。如果你绑定了一个 T
,Guice 允许你为那个 T
注入一个 Provider
或调用 Injector.getProvider
,即使你自己没有明确创建一个 Provider。请参阅维基上的 Built-In Bindings 页面,
或 Injector docs(强调我的):
Contains several default bindings:
- This Injector instance itself
- A
Provider<T>
for each binding of type T
- The Logger for the class being injected
- The Stage in which the Injector was created
相反,这样做:
public class ModuleBinder extends AbstractModule {
@Override
protected void configure() {
bind(DatabaseControllerInterface.class)
.to(DatabaseControllerImpl.class).asEagerSingleton();
bind(AnalyzerInterface.class)
.to(AnalyzerImpl.class).asEagerSingleton();
bind(SystemAdministrationInterface.class)
.to(SystemAdministrationImpl.class).asEagerSingleton();
bind(LogInServiceInterface.class)
.to(LogInServiceImpl.class);
}
}
然后您可以像现在一样选择,注入 T
或 Provider<T>
并根据需要调用 getInstance
或 getProvider
。
如果您的供应商绝对必要,特别是如果他们实际上从其他系统或服务定位器接收实例,另一种选择是添加您的 @Inject
字段像在 Provider bindings wiki page and pass them into your constructor, or to just inject a MembersInjector<T>
:
中那样进入它们
public class LogInServiceProvider implements Provider<LogInServiceInterface> {
@Inject MembersInjector<LogInServiceImpl> logInServiceImplInjector;
@Override
public LogInServiceInterface get() {
LogInServiceImpl logInServiceImpl = YourExternalDep.getLogInService();
logInServiceImplInjector.injectMembers(logInServiceImpl);
return logInServiceImpl;
}
}
但是,这种显式提供程序解决方案不是惯用的 Guice,只能与外部或遗留代码一起使用。 Guice 存在的全部原因是自动化样板文件,让您的系统清晰灵活地组合在一起。提供者是一个实现细节;让 Guice 为您创建它们。
我对 Guice 比较陌生,有些事情仍然让我很难过。 我的具体问题是,您如何处理 Guice 中的嵌套注入。 示例:
Class A 通过 @Inject
使用 Class B,Class B 使用 Class C.
明确:
我绑定到提供商的模块。
public class ModuleBinder extends AbstractModule {
@Override
protected void configure() {
bind(DatabaseControllerInterface.class)
.toProvider(DatabaseControllerProvider.class).asEagerSingleton();
bind(AnalyzerInterface.class)
.toProvider(AnalyzerProvider.class).asEagerSingleton();
bind(SystemAdministrationInterface.class)
.toProvider(SystemAdministrationProvider.class).asEagerSingleton();
bind(LogInServiceInterface.class)
.toProvider(LogInServiceProvider.class);
}
}
DatabaseControllerProvider:
public class DatabaseControllerProvider implements Provider<DatabaseControllerInterface> {
@Override
public DatabaseControllerInterface get() {
return new DatabaseControllerImpl();
}
}
LogInServiceProvider:
public class LogInServiceProvider implements Provider<LogInServiceInterface> {
@Override
public LogInServiceInterface get() {
return new LogInServiceImpl();
}
}
最后,LogInService 使用:
public class LogInServiceImpl implements LogInServiceInterface{
@Inject
private DatabaseControllerProvider databaseControllerProvider;
private final DatabaseControllerInterface databaseController;
public LogInServiceImpl() {
this.databaseController = databaseControllerProvider.get();
}
@Override
public User register(final String mail, final String userName, final String password) {
databaseController.registerUser(userName, mail, password, UserRole.ADMIN);
}
}
那么电话是:
public class Test() {
public static test() {
final Injector injector = Guice.createInjector(new ModuleBinder());
logInService = injector.getInstance(LogInServiceInterface.class);
logInService.registerUser("test", "test", "test");
}
}
我知道你们中的大多数人都会厌倦那些代码,但是嘿,我是 Guice 的初学者,所以请对我温柔一些。
我想使用构造函数注入,我已经意识到可以考虑字段注入"evil"。您知道如何通过保留提供者(我需要他们)来实现它吗?
使用示例中的注入在 "second" 级别上没有任何作用,LogInServiceImpl
中的 DatabaseControllerImpl
是 null
。
我是不是配置有误?我是否误解了 Provides and/or 模块的用法?
我希望有人能够并且愿意帮助我。如果您需要更多信息,post 评论。
谨致问候,
约瑟夫背囊
您的直接回答:您在不支持字段注入的提供程序中调用 new T();
。
首先,一个真正节省时间的方法:不要保留您的显式提供程序。如果你绑定了一个 T
,Guice 允许你为那个 T
注入一个 Provider
或调用 Injector.getProvider
,即使你自己没有明确创建一个 Provider。请参阅维基上的 Built-In Bindings 页面,
或 Injector docs(强调我的):
Contains several default bindings:
- This Injector instance itself
- A
Provider<T>
for each binding of typeT
- The Logger for the class being injected
- The Stage in which the Injector was created
相反,这样做:
public class ModuleBinder extends AbstractModule {
@Override
protected void configure() {
bind(DatabaseControllerInterface.class)
.to(DatabaseControllerImpl.class).asEagerSingleton();
bind(AnalyzerInterface.class)
.to(AnalyzerImpl.class).asEagerSingleton();
bind(SystemAdministrationInterface.class)
.to(SystemAdministrationImpl.class).asEagerSingleton();
bind(LogInServiceInterface.class)
.to(LogInServiceImpl.class);
}
}
然后您可以像现在一样选择,注入 T
或 Provider<T>
并根据需要调用 getInstance
或 getProvider
。
如果您的供应商绝对必要,特别是如果他们实际上从其他系统或服务定位器接收实例,另一种选择是添加您的 @Inject
字段像在 Provider bindings wiki page and pass them into your constructor, or to just inject a MembersInjector<T>
:
public class LogInServiceProvider implements Provider<LogInServiceInterface> {
@Inject MembersInjector<LogInServiceImpl> logInServiceImplInjector;
@Override
public LogInServiceInterface get() {
LogInServiceImpl logInServiceImpl = YourExternalDep.getLogInService();
logInServiceImplInjector.injectMembers(logInServiceImpl);
return logInServiceImpl;
}
}
但是,这种显式提供程序解决方案不是惯用的 Guice,只能与外部或遗留代码一起使用。 Guice 存在的全部原因是自动化样板文件,让您的系统清晰灵活地组合在一起。提供者是一个实现细节;让 Guice 为您创建它们。