【问题标题】:Got NPE after integrating play framework with play-redis将play框架与play-redis集成后得到NPE
【发布时间】:2022-01-10 13:48:10
【问题描述】:

将play-redis(https://github.com/KarelCemus/play-redis)与play框架集成后,收到请求时出现错误:

[20211204 23:20:48.350][HttpErrorHandler.scala:272:onServerError][E] Error while handling error
java.lang.NullPointerException: null
    at play.api.http.HttpErrorHandlerExceptions$.convertToPlayException(HttpErrorHandler.scala:377)
    at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:367)
    at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:264)
    at play.core.server.Server$$anonfun$handleErrors$1$1.applyOrElse(Server.scala:109)
    at play.core.server.Server$$anonfun$handleErrors$1$1.applyOrElse(Server.scala:105)
    at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:35)
    at play.core.server.Server$.getHandlerFor(Server.scala:129)
    at play.core.server.AkkaHttpServer.handleRequest(AkkaHttpServer.scala:317)
    at play.core.server.AkkaHttpServer.$anonfun$createServerBinding$1(AkkaHttpServer.scala:224)
    at akka.stream.impl.fusing.MapAsync$$anon$30.onPush(Ops.scala:1297)
    at akka.stream.impl.fusing.GraphInterpreter.processPush(GraphInterpreter.scala:541)
    at akka.stream.impl.fusing.GraphInterpreter.processEvent(GraphInterpreter.scala:495)
    at akka.stream.impl.fusing.GraphInterpreter.execute(GraphInterpreter.scala:390)
    at akka.stream.impl.fusing.GraphInterpreterShell.runBatch(ActorGraphInterpreter.scala:625)
    at akka.stream.impl.fusing.GraphInterpreterShell$AsyncInput.execute(ActorGraphInterpreter.scala:502)
    at akka.stream.impl.fusing.GraphInterpreterShell.processEvent(ActorGraphInterpreter.scala:600)
    at akka.stream.impl.fusing.ActorGraphInterpreter.akka$stream$impl$fusing$ActorGraphInterpreter$$processEvent(ActorGraphInterpreter.scala:775)
    at akka.stream.impl.fusing.ActorGraphInterpreter$$anonfun$receive$1.applyOrElse(ActorGraphInterpreter.scala:790)
    at akka.actor.Actor.aroundReceive(Actor.scala:537)
    at akka.actor.Actor.aroundReceive$(Actor.scala:535)
    at akka.stream.impl.fusing.ActorGraphInterpreter.aroundReceive(ActorGraphInterpreter.scala:691)
    at akka.actor.ActorCell.receiveMessage(ActorCell.scala:579)
    at akka.actor.ActorCell.invoke(ActorCell.scala:547)
    at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:270)
    at akka.dispatch.Mailbox.run(Mailbox.scala:231)
    at akka.dispatch.Mailbox.exec(Mailbox.scala:243)
    at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
    at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.topLevelExec(ForkJoinPool.java:1020)
    at java.base/java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1656)
    at java.base/java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1594)
    at java.base/java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:183)

我确定原因一定是play-redis,因为没有它,应用程序运行顺利。特别是,我使用配置提供程序的自定义实现,因为需要通过调用名称服务的 rest API 来获取 ip 和端口。

@Singleton
class CustomRedisInstance @Inject() (
    config: Configuration,
    polarisExtensionService: PolarisExtensionService,
    @NamedCache("redisConnection") redisConnectionCache: AsyncCacheApi)(implicit
    asyncExecutionContext: AsyncExecutionContext)
    extends RedisStandalone
    with RedisDelegatingSettings {

  val pathPrefix = "play.cache.redis"

  def name = "play"

  private def defaultSettings =
    RedisSettings.load(
      // this should always be "play.cache.redis"
      // as it is the root of the configuration with all defaults
      config.underlying,
      "play.cache.redis")

  def settings: RedisSettings = {
    RedisSettings
      .withFallback(defaultSettings)
      .load(
        // this is the path to the actual configuration of the instance
        //
        // in case of named caches, this could be, e.g., "play.cache.redis.instances.my-cache"
        //
        // in that case, the name of the cache is "my-cache" and has to be considered in
        // the bindings in the CustomCacheModule (instead of "play", which is used now)
        config.underlying,
        "play.cache.redis")
  }


  def host: String = {
    val connectionInfoFuture = getConnectionInfoFromPolaris
    Try(Await.result(connectionInfoFuture, 10.seconds)) match {
      case Success(extractedVal) => extractedVal.host
      case Failure(_)            => config.get[String](s"$pathPrefix.host")
      case _                     => config.get[String](s"$pathPrefix.host")
    }
  }

  def port: Int = {
    val connectionInfoFuture = getConnectionInfoFromPolaris
    Try(Await.result(connectionInfoFuture, 10.seconds)) match {
      case Success(extractedVal) => extractedVal.port
      case Failure(_)            => config.get[Int](s"$pathPrefix.port")
      case _                     => config.get[Int](s"$pathPrefix.port")
    }
  }

  def database: Option[Int] = Some(config.get[Int](s"$pathPrefix.database"))

  def password: Option[String] = Some(config.get[String](s"$pathPrefix.password"))

}

play-redis 本身没有错误日志。经过所有这些努力阅读手册和示例后,我应该转向JedisLettuce?现在没有希望了。

【问题讨论】:

    标签: redis


    【解决方案1】:

    原因是我想将RedisCaffeine 一起使用,这会导致冲突,如文档所述,需要将application.conf 中的default-cache 重命名为redis

    play.modules.enabled += play.api.cache.redis.RedisCacheModule
    # provide additional configuration in the custom module
    play.modules.enabled += services.CustomCacheModule
    
    play.cache.redis {
       # do not bind default unqualified APIs
       bind-default: false
    
       # name of the instance in simple configuration,
       # i.e., not located under `instances` key
       # but directly under 'play.cache.redis'
       default-cache: "redis"
    
       source = custom
       host = 127.0.0.1
        # redis server: port
       port = 6380
        # redis server: database number (optional)
       database = 0
        # authentication password (optional)
       password = "#########"
       refresh-minute = 10
    }
    

    所以在CustomCacheModule中,NamedCacheImpl的输入参数需要由play改为redis

    class CustomCacheModule extends AbstractModule {
      override def configure(): Unit = {
        // NamedCacheImpl's input used to be "play"
        bind(classOf[RedisInstance]).annotatedWith(new NamedCacheImpl("redis")).to(classOf[CustomRedisInstance])
        ()
      }
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-03-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多