我试图将一个带注释的变量注入REQUEST范围:
Map<Key<?>, Object> seedMap = ImmutableMap.<Key<?>, Object>builder().
put(Key.get(String.class, Names.named("name")), name).build();
return ServletScopes.scopeRequest(new InjectingCallable<>(injector,
GetModule.class), seedMap).call();
其中,InjectingCallable在REQUEST范围内注入GetModule:
/**
* A Callable that is constructed in one scope and injects a Callable into a potentially separate
* scope.
* <p/>
* @param <V> the type of object returned by the Callable
* @author Gili Tzabari
*/
public final class InjectingCallable<V> implements Callable<V>
{
private final Injector injector;
private final Class<? extends Callable<V>> delegate;
/**
* Creates a new InjectingCallable.
* <p/>
* @param injector the Guice injector
* @param delegate the class to inject and delegate to
*/
public InjectingCallable(Injector injector, Class<? extends Callable<V>> delegate)
{
Preconditions.checkNotNull(injector, "injector may not be null");
Preconditions.checkNotNull(delegate, "delegate may not be null");
this.injector = injector;
this.delegate = delegate;
}
@Override
public V call() throws Exception
{
return injector.getInstance(delegate).call();
}
}
GetModule定义如下:
@RequestScoped
private static class GetModule implements Callable<Module>
{
private final String name;
private final Session session;
@Inject
public GetModule(@Named("name") String name, Session session)
{
this.name = name;
this.session = session;
}
}
当我运行此代码时,我收到此错误:
1) No implementation for java.lang.String annotated with @com.google.inject.name.Named(value=name) was bound.
while locating java.lang.String annotated with @com.google.inject.name.Named(value=name)
如果我将同一个变量绑定到全局范围,它就可以工作。如果我删除注释,它的工作原理。此问题似乎特定于Request-scoped注释变量。有什么想法吗?
答案 0 :(得分:5)
问题是您没有此类型的绑定。仅仅因为您明确播种该值并不意味着您不必绑定它。你可以说:
bind(String.class)
.annotatedWith(Names.named("name"))
.toProvider(Providers.<String>of(null));
然后如果name
变量的值为"foo"
,您将会注入"foo"
,因为您正在播种它。播种值会将其置于作用域(这只是一个缓存)中,这样Guice就不会运行该值的提供者。通过使用null提供程序,如果没有播种,可以让值放大。
简而言之,Guice要求您指定一种方法来配置每个依赖项,无论您是否计划手动设置范围(这应该是一个相当罕见的事情)。
一些未经请求的建议:
- 请避免注射注射器。它使得更难以发现这类问题。最好有一个“根对象”。这是您需要调用injector.getInstance
来创建的单个对象。对于很多应用程序,这可能只是您的应用程序服务器。 (例如 - injector.getInstance(MyServer.class).startServer()
)。为什么这对你有帮助?它使得在启动时更容易检测到所有依赖项都得到满足。如果在请求期间注入注入器并且可以调用它来创建任意对象,那么在运行时期间由于缺少绑定而导致出现一些设置错误的风险。此外,如果您在早期执行所有getInstance调用,则更容易编写为您执行此操作的测试,以便您只需运行测试即可知道您的Guice绑定已得到满足。
更新:
嗯,你基本上做了我做的事吗?如果是这样,我上面的解释解释了为什么这样做: - )。如果我将同一个变量绑定到全局范围,它就可以工作。
如果删除注释,则可以正常工作。
这有效的原因是因为Guice确实对String
有绑定,因为String
有一个空的构造函数:-)。基本上你必须有一个@Inject
能够构造函数,一个无参数构造函数或一个绑定类型的提供者。