@RequestScoped
对象的引用?seedMap
有什么意义?是否意味着覆盖默认绑定?答案 0 :(得分:12)
回答我自己的问题:
static
或顶级课程是您的朋友。Callable
传递给ServletScopes.scopeRequest()之前注入Callable
。因此,您必须注意seedMap
包含的字段。更多内容如下。Callable
允许您将非范围对象注入范围。这很危险,所以要注意你注射的东西。那么,最好的方法是什么?
如果您不需要将用户对象传递到Callable
:在请求范围之外注入Callable
,并将其传递到ServletScopes.scopeRequest() 。 Provider<Foo>
可能只会引用Foo
而不是Callable
,否则您最终会在请求范围之外注入实例。
如果您需要将用户对象传递到Callable
,请继续阅读。
假设您有一个将名称插入数据库的方法。我们有两种方法将名称传递给InsertName
。
方法1 :使用子模块传递用户对象:
定义Callable
,一个插入数据库的@RequestScoped
private static class InsertName implements Callable<Boolean>
{
private final String name;
private final Connection connection;
@Inject
public InsertName(@Named("name") String name, Connection connection)
{
this.name = name;
this.connection = connection;
}
@Override
public Boolean call()
{
try
{
boolean nameAlreadyExists = ...;
if (!nameAlreadyExists)
{
// insert the name
return true;
}
return false;
}
finally
{
connection.close();
}
}
}
:
requestInjector.scopeRequest(InsertName.class, new AbstractModule()
{
@Override
protected void configure()
{
bind(String.class).annotatedWith(Names.named("name")).toInstance("John");
}
})
绑定子模块中的所有用户对象,并使用RequestInjector.scopeRequest()来调用可调用范围:
RequestInjector
我们在请求之外实例化Callable
,然后在请求中注入第二个Callable
。第二个Foo
可以直接引用import com.google.common.base.Preconditions;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.servlet.ServletScopes;
import java.util.Collections;
import java.util.Map;
import java.util.concurrent.Callable;
/**
* Injects a Callable into a non-HTTP request scope.
* <p/>
* @author Gili Tzabari
*/
public final class RequestInjector
{
private final Map<Key<?>, Object> seedMap = Collections.emptyMap();
private final Injector injector;
/**
* Creates a new RequestInjector.
*/
@Inject
private RequestInjector(Injector injector)
{
this.injector = injector;
}
/**
* Scopes a Callable in a non-HTTP request scope.
* <p/>
* @param <V> the type of object returned by the Callable
* @param callable the class to inject and execute in the request scope
* @param modules additional modules to install into the request scope
* @return a wrapper that invokes delegate in the request scope
*/
public <V> Callable<V> scopeRequest(final Class<? extends Callable<V>> callable,
final Module... modules)
{
Preconditions.checkNotNull(callable, "callable may not be null");
return ServletScopes.scopeRequest(new Callable<V>()
{
@Override
public V call() throws Exception
{
return injector.createChildInjector(modules).getInstance(callable).call();
}
}, seedMap);
}
}
(不需要提供者),因为它是在请求范围内注入的。
Callable
方法2 :在引用Provider<Foo>
的请求之外注入call()
。然后,get()
方法可以seedMap
请求范围内的实际值。对象对象通过InsertName
传递(我个人觉得这种方法反直觉):
定义Callable
,一个插入数据库的Providers
。请注意,与方法1不同,我们必须使用@RequestScoped
private static class InsertName implements Callable<Boolean>
{
private final Provider<String> name;
private final Provider<Connection> connection;
@Inject
public InsertName(@Named("name") Provider<String> name, Provider<Connection> connection)
{
this.name = name;
this.connection = connection;
}
@Override
public Boolean call()
{
try
{
boolean nameAlreadyExists = ...;
if (!nameAlreadyExists)
{
// insert the name
return true;
}
return false;
}
finally
{
connection.close();
}
}
}
:
No implementation for String annotated with @com.google.inject.name.Named(value=name) was bound.
为您要传入的类型创建虚假绑定。如果不这样做,您将获得:ImmutableMap<Key<?>, Object> seedMap = ImmutableMap.<Key<?>, Object>of(Key.get(String.class, Names.named("name")), "john");
https://stackoverflow.com/a/9014552/14731解释为何需要这样做。
使用所需的值填充seedMap:
ServletScopes.scopeRequest()
调用ServletScopes.scopeRequest(injector.getInstance(InsertName.class), seedMap);
:
{{1}}