用Java获取当前的Play会话()

时间:2016-02-27 20:50:58

标签: java spring playframework-2.3

我有这堂课:

package ds;

import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import play.mvc.Http;

public class MyRoutingDataSource extends AbstractRoutingDataSource {

    @Override
    protected String determineCurrentLookupKey() {
        return Http.Context.current().session().get("currentDB");
    }
}

但是当我想进入Play会话时,我有这个错误:

Caused by: java.lang.RuntimeException: There is no HTTP Context available from here.
at play.mvc.Http$Context.current(Http.java:34) ~[play_2.10-2.3.10.jar:2.3.10]
at play.mvc.Controller.session(Controller.java:72) ~[play_2.10-2.3.10.jar:2.3.10]

我也尝试过使用HttpExecution.defaultContext()和他的HttpExecutionContext但是它不能被强制转换为我需要的Http.Context。

我正在考虑获取请求标题但当然我不知道如何从我的类中处理它并从请求中确定会话

1 个答案:

答案 0 :(得分:2)

您无法访问该层中的播放上下文原因超出范围。在AbstractRoutingDatasource的文档中:

https://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/jdbc/datasource/lookup/AbstractRoutingDataSource.html

班级的主要描述是:

  

路由getConnection()调用的抽象DataSource实现   基于查找键的各种目标DataSource之一。后者   通常(但不一定)通过某些人确定   线程绑定事务上下文

因此,这个类建议获取当前上下文信息的方法应该是使用线程绑定事务上下文。

现在,PlayFramework线程上下文安全吗?阅读Play文档:

https://www.playframework.com/documentation/2.3.x/ThreadPools#Java-thread-locals

  

Play中的Java代码使用本地线程来查找上下文   当前HTTP请求等信息。 Scala代码不需要   使用线程局部因子,因为它可以使用隐式参数传递   上下文。线程本地在Java中使用,以便Java代码可以   访问上下文信息而无需传递上下文   参数无处不在。

因此,如果您使用的是Java实现,则可以将ThreadLocals用作组件之间的上下文通道。如果您创建自己的线程池,请小心,因为在同一文档中有警告:

  

默认对象包装默认用户线程池。如果你想   做你自己的线程然后你应该使用HttpExecution类   帮助方法自己获取ExecutionContextExecutor对象。

但是,如果您未在应用中使用自定义线程池,则不会出现问题。

说,你要做的是:

  1. 为要用作路由器的对象定义ThreadLocalContext。

  2. 放入上下文。 (如果您使用像Deadbolt这样的授权框架甚至实现新的请求过滤器,您可以在控制器,安全控制器中执行此操作。)

  3. 在AbstractRoutingDataSource中读取ThreadLocal上下文。

  4. 重要!不要忘记清除Thread-Local或者你可能面临内存泄漏。

    第1步:

    public class RequestContext {
    
       private static final ThreadLocal<String> contextHolder = 
                new ThreadLocal<String>();
    
       public static void setRoutingKey(String key) {
          contextHolder.set(key);
       }
    
       public static String getRoutingKey() {
          return (String) contextHolder.get();
       }
    
       public static void clearRoutingKey() {
          contextHolder.remove();
       }
    }
    

    第2步:

    //Demostrative code, not tested, not even compiled
    public static void myController() {
       RoutingContext.setRoutingKey(Play.Context.request()); 
       return bla;
    }
    

    第3步:

    @Override
    protected Object determineCurrentLookupKey() {
      String datasource = RoutingContext.getRoutingKey();
      RoutingContext.clearRoutingKey();
      return datasource;
    }
    

    问候!

相关问题