我可能對晚會有點遲,但這對我有用。使用Play! 2.4和Guice 4.0。
我在試圖找出如何解決將實例作用於Http.Context.current
範圍的問題時登陸此貼子。
這裏是我的解決方案:
import com.google.common.collect.Maps;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.Scope;
import com.google.inject.Scopes;
import play.mvc.Http;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Allows objects to be bound to Play! Http.Context.current.args with a ThreadLocal fallback.
*/
public class HttpContextScope implements Scope {
private static final ThreadLocal<Context> httpContextScopeContext = new ThreadLocal<>();
enum NullableObject {
INSTANCE
}
@Override
public <T> Provider<T> scope(final Key<T> key, final Provider<T> provider) {
return new Provider<T>() {
@Override
public T get() {
Http.Context currentContext = Http.Context.current();
if (currentContext == null) {
Context context = httpContextScopeContext.get();
if (context != null) {
T t = (T) context.map.get(key);
if (t == NullableObject.INSTANCE) {
return null;
}
if (t == null) {
t = provider.get();
if (!Scopes.isCircularProxy(t)) {
context.map.put(key, t != null ? t : NullableObject.INSTANCE);
}
}
return t;
}
}
String name = key.toString();
synchronized (currentContext) {
Object obj = currentContext.args.get(name);
if (obj == NullableObject.INSTANCE) {
return null;
}
T t = (T) obj;
if (t == null) {
t = provider.get();
if (!Scopes.isCircularProxy(t)) {
currentContext.args.put(name, t != null ? t : NullableObject.INSTANCE);
}
}
return t;
}
}
};
}
@Override
public String toString() {
return "Http.Context.ARGS";
}
private static class Context implements ContextScoper {
final Map<Key, Object> map = Maps.newHashMap();
final Lock lock = new ReentrantLock();
@Override
public CloseableScope open() {
lock.lock();
final Context previous = httpContextScopeContext.get();
httpContextScopeContext.set(this);
return new CloseableScope() {
@Override
public void close() {
httpContextScopeContext.set(previous);
lock.unlock();
}
};
}
}
}
的ContextScoper
和ContextScoper.CloseableScope
接口:
import java.io.Closeable;
public interface ContextScoper {
CloseableScope open();
interface CloseableScope extends Closeable {
@Override
void close();
}
}
而且ScopeAnnotation
:
import com.google.inject.ScopeAnnotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@ScopeAnnotation
public @interface HttpContextScoped {
}
和接線這一切:
public class AppModule extends AbstractModule {
@Override
protected void configure() {
HttpContextScope httpContextScope = new HttpContextScope();
bindScope(HttpContextScoped.class, httpContextScope);
}
@Provides
@HttpContextScoped
public TheThing providesTheThing() {
return new TheThing();
}
}
FWIW,這是谷歌自己的ServletScopes found here的改編:
聲明:我沒有做的ThreadLocal
回退測試尚未完成,所以我不能肯定地說這部分是否是固體。
乾杯!
謝謝。這有助於我開始。 – 2014-09-03 11:03:01