2014-09-02 78 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

相關問題