Playframework 2.0 如何使用Play Framework';Google Guice中的请求和会话范围?
在我的Play(Java)框架项目中,我正在使用Guice进行依赖项注入,并且正在努力理解如何最好地将“会话”的概念与Guice和Play结合使用 我知道Play是无状态的,除了可以在cookie中存储值之外,实际上没有会话的概念。我对Guice和Play的理解是,虽然Guice文档描述了支持不同的作用域(单例、会话、请求、无作用域),但因为我们正在用每个请求实例化一个新的注入器,所以仅适用于Play的作用域是单例和“无作用域” 我感到困惑的是:使用Guice和Play“模拟”会话的最佳方式是什么?我应该定义“自定义范围”吗 请注意,我正在使用Redis存储会话数据。以下是我正在考虑的一些选择:Playframework 2.0 如何使用Play Framework';Google Guice中的请求和会话范围?,playframework-2.0,guice,Playframework 2.0,Guice,在我的Play(Java)框架项目中,我正在使用Guice进行依赖项注入,并且正在努力理解如何最好地将“会话”的概念与Guice和Play结合使用 我知道Play是无状态的,除了可以在cookie中存储值之外,实际上没有会话的概念。我对Guice和Play的理解是,虽然Guice文档描述了支持不同的作用域(单例、会话、请求、无作用域),但因为我们正在用每个请求实例化一个新的注入器,所以仅适用于Play的作用域是单例和“无作用域” 我感到困惑的是:使用Guice和Play“模拟”会话的最佳方式是什
- 编写一个单例Guice类,作为Redis的薄包装器
- 编写一个“无作用域”Guice类,该类使用
对象来获取和设置Java对象ctx()
这里有没有标准实践,或者我在Play app中设置会话概念时可能遵循的任何其他指导原则?游戏中没有会话。如果你想要一个会话,你必须使用action composition和WrappedRequest提供一个:在这种情况下,你需要一个带有会话id的cookie,然后你需要一个服务,在Redis中查找会话id并返回会话数据,这样你就可以把它放在WrappedRequest中
一旦您获得了一个公开会话数据的WrappedRequest,您就可以引用它:request.user、request.context等。是的,您可以使用request.injector直接公开Guice查找,但这有点黑客化,而且不是类型安全的。没有会话。如果你想要一个会话,你必须使用action composition和WrappedRequest提供一个:在这种情况下,你需要一个带有会话id的cookie,然后你需要一个服务,在Redis中查找会话id并返回会话数据,这样你就可以把它放在WrappedRequest中
一旦你有了一个公开会话数据的WrappedRequest,你就可以引用它:request.user、request.context等等。是的,你可以用request.injector直接公开Guice查找,但这有点黑客化,而且不是类型安全的。我参加聚会可能有点晚,但这对我来说是有效的。使用游戏!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();
}
};
}
}
}
以及范围注释
:
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,这是对谷歌自己的ServletScope的改编:
免责声明:我还没有完成ThreadLocal
回退测试,所以我不能确定这部分是否可靠
干杯 我参加聚会可能会晚一点,但这对我来说很有效。使用游戏!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();
}
};
}
}
}
以及范围注释
:
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,这是对谷歌自己的ServletScope的改编:
免责声明:我还没有完成ThreadLocal
回退测试,所以我不能确定这部分是否可靠
干杯 谢谢。这有助于我行动起来。谢谢。这有助于我开始。ContextScope和CloseableScope来自哪里?它似乎不是Guice的一部分。ContextScope和CloseableScope来自哪里?这似乎不是Guice的一部分。