2014-09-02 80 views
1

我在我的Play(Java)框架项目中使用Guice进行依赖注入,并努力理解“会话”的概念如何最好地与Guice和Play一起使用?如何在Google Guice中使用Play Framework的请求和会话范围?

我知道Play是无状态的,实际上没有会话的概念,除了可以将值存储在cookie中。我对Guice和Play的理解是,虽然Guice文档描述了支持不同范围(单例,会话,请求,无范围),因为我们正在为每个请求实例化一个新的注入器,唯一适用于Play的范围是单例,“不范围”。

我感到困惑的地方是:什么是使用Guice和Play“模拟”会话的最佳方式?我应该定义一个“自定义范围”吗?

请注意,我使用Redis来存储会话数据。这里有一些选择,我想:

  • 写充当围绕Redis的瘦包装
  • 编写使用ctx()对象“无范围”吉斯类来获取和设置Java的一个单类吉斯物体

这里是否有标准做法,或者我可能遵循的任何其他指南在我的Play应用中设置会话概念?

回答

4

Play中没有会话。如果你想要一个会话,你将不得不提供一个使用动作组合和WrappedRequest:在这种情况下,你需要一个带有会话ID的cookie,然后你需要一个服务在Redis中查找会话ID并返回你的会话数据,所以你可以把它放在WrappedRequest中。一旦你有一个公开你的会话数据的WrappedRequest,你可以参考它:request.user,request.context等。是的,你可以直接使用request.injector暴露Guice查找,但那是一个有点多哈哈,而不是类型安全。

+0

谢谢。这有助于我开始。 – 2014-09-03 11:03:01

3

我可能对晚会有点迟,但这对我有用。使用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(); 
       } 
      }; 
     } 
    } 
} 

ContextScoperContextScoper.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回退测试尚未完成,所以我不能肯定地说这部分是否是固体。

干杯!

+0

ContextScoper和CloseableScope从哪里来?它似乎不是Guice的一部分。 – 2016-06-22 16:11:52

相关问题