Guice:无法在Request范围中注入带注释的类型

我试图将一个带注释的变量注入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. * 

* @param the type of object returned by the Callable * @author Gili Tzabari */ public final class InjectingCallable implements Callable { private final Injector injector; private final Class<? extends Callable> delegate; /** * Creates a new InjectingCallable. *

* @param injector the Guice injector * @param delegate the class to inject and delegate to */ public InjectingCallable(Injector injector, Class<? extends Callable> 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 { 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注释变量。 有任何想法吗?

问题是您没有此类型的绑定。 仅仅因为您明确播种该值并不意味着您不必绑定它。 你可以说:

 bind(String.class) .annotatedWith(Names.named("name")) .toProvider(Providers.of(null)); 

然后如果name变量的值为"foo" ,你将会注入"foo"因为你正在播种它。 播种值会将其置于作用域(这只是一个缓存)中,这样Guice就不会运行该值的提供者。 通过使用null提供程序,如果没有播种,您可以让值放大。

简而言之,Guice要求您指定一种方法来配置每个依赖项,无论您是否计划手动种子范围(这应该是一个相当罕见的事情)。

一些未经请求的建议: – 请避免注射注射器。 它使得更难以发现这些问题。 最好有一个“根对象”。 这是您需要调用injector.getInstance来创建的单个对象。 对于很多应用程序,这可能只是您的应用程序服务器。 (例如 – injector.getInstance(MyServer.class).startServer() )。 为什么这对你有帮助? 它使得在启动时更容易检测到所有依赖项都得到满足。 如果在请求期间注入注入器并且可以调用它来创建任意对象,则在运行时期间由于缺少绑定而导致出现一些设置错误的风险。 此外,如果您在早期执行所有getInstance调用,则更容易编写为您执行此操作的测试,以便您可以简单地运行测试以了解您的Guice绑定是否满足。

更新:

如果我将相同的变量绑定到全局范围,它就可以工作。

嗯,你基本上做了我做的事吗? 如果是这样,我上面的解释解释了为什么有效:-)。

如果我删除注释,它的工作原理。

这个工作的原因是因为Guice确实有String的绑定,因为String有一个空的构造函数:-)。 基本上,您必须有一个@Inject -able构造函数,一个无参数构造函数或一个绑定类型的提供程序。