我有这个课:

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");
    }
}


但是,当我想进入播放会话时,会出现以下错误:

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。

我正在考虑获取请求标头,但我当然不知道如何从我的班级处理它,并根据请求确定会话

最佳答案

由于该层超出范围,因此您无法访问“播放上下文”。在AbstractRoutingDatasource的文档中:

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

该类的主要描述是:


  路由getConnection()调用的抽象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对象的帮助器方法。


但是,如果您没有在应用程序中使用自定义线程池,那将不是问题。

也就是说,您要做的是:


为要用作路由器的对象定义ThreadLocalContext。
放在上下文中。 (如果您使用的是Deadbolt之类的授权框架,或者甚至实现了新的请求过滤器,则可以在控制器中,在安全控制器中进行操作。)
在AbstractRoutingDataSource中读取ThreadLocal上下文。


重要!不要忘了清理本地线程,否则您可能会遇到内存泄漏。

步骤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;
}


第三步:

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


问候!

关于java - 在Java中获取当前的Play session(),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/35675298/

10-14 13:06
查看更多