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

Gil*_*ili 2 java guice

我试图将一个带注释的变量注入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();
Run Code Online (Sandbox Code Playgroud)

其中,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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

当我运行此代码时,我收到此错误:

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)
Run Code Online (Sandbox Code Playgroud)

如果我将相同的变量绑定到全局范围,它就可以工作.如果我删除注释,它的工作原理.此问题似乎特定于Request-scoped注释变量.有任何想法吗?

Tom*_*Tom 5

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

bind(String.class)
    .annotatedWith(Names.named("name"))
    .toProvider(Providers.<String>of(null));
Run Code Online (Sandbox Code Playgroud)

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

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

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

更新:

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

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

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

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