找不到 ActorSystem 的隐式值

Could not find implicit value for ActorSystem

我刚开始使用 Akka 和 Scala,我正在尝试使用 Akka Streams 连接到 WebSocket。我在下面创建了 SocketActor 并尝试从 main 方法实例化。

这是我的 SocketActor:

package com.lightbend.akka.sample

import akka.actor.{Actor, Props}
import akka.Done
import akka.http.scaladsl.Http
import akka.stream.scaladsl._
import akka.http.scaladsl.model.ws._
import scala.concurrent.Future


object SocketActor {

  def props(coinApiIdentifier: String): Props = Props(new SocketActor(coinApiIdentifier))

  case object Start

  case object Stop

}

class SocketActor(val ticker: String) extends Actor {

  import SocketActor._


  // Future[Done] is the materialized value of Sink.foreach,
  // emitted when the stream completes
  private val incoming: Sink[Message, Future[Done]] =
  Sink.foreach[Message] {
    case message: TextMessage.Strict =>
      println(message.text)
  }

  // send this as a message over the WebSocket
  private val outgoing = Source.single(TextMessage("hello world!"))

  // flow to use (note: not re-usable!)
  private val webSocketFlow = Http().webSocketClientFlow(WebSocketRequest("wss://api.com/v1/"))

  // the materialized value is a tuple with
  // upgradeResponse is a Future[WebSocketUpgradeResponse] that
  // completes or fails when the connection succeeds or fails
  // and closed is a Future[Done] with the stream completion from the incoming sink
  private val graph =
  outgoing
    .viaMat(webSocketFlow)(Keep.right) // keep the materialized Future[WebSocketUpgradeResponse]
    .toMat(incoming)(Keep.both) // also keep the Future[Done]


  override def receive: PartialFunction[Any, Unit] = {
    case Start =>
      println("Start message received.")
      graph.run()
  }
}

还有我的主要方法:

object AkkaQuickstart extends App {

  // Create the 'helloAkka' actor system
  val system: ActorSystem = ActorSystem("test")
  val materializer: ActorMaterializer = ActorMaterializer()

  val socketActor: ActorRef =
    system.actorOf(SocketActor.props("hello"), "socket-actor")

  socketActor ! Start
}

不幸的是,我得到了错误:

Error:(38, 35) could not find implicit value for parameter system: akka.actor.ActorSystem private val webSocketFlow = Http().webSocketClientFlow(WebSocketRequest("wss://api.com/v1/"))

我试过将一些 implicit 参数传递给 SocketActor 的构造函数,但效果不佳。由于某种原因,ActorSystem 似乎不在范围内。如何让我的 system 进入 SocketActor 中的 Http() 函数?

定义隐式 val:

class SocketActor(val ticker: String) extends Actor {
  implicit val sys = context.system
  // ...
}

这将提供 Http 对象所期望的隐式 ActorSystem

您的代码还有另一个问题:您的 actor 中的流不会 运行 因为范围内没有物化器。解决这个问题的一种方法是在 actor 内部创建物化器:

class SocketActor(val ticker: String) extends Actor {
  implicit val sys = context.system
  implicit val mat = ActorMaterializer()(context)
  // ...
}

请注意,如果实体化器定义为 implicit val mat = ActorMaterializer(),由于 implicit val sys = context.system,它会隐式使用 context.system。相反,实体化器是使用 actor 的 context 显式创建的。这样做是因为 documentation:

中的警告

Do not create new actor materializers inside actors by passing the context.system to it. This will cause a new ActorMaterializer to be created and potentially leaked (unless you shut it down explicitly) for each such actor. It is instead recommended to either pass-in the Materializer or create one using the actor’s context.

允许 actor 的创建者重用 materializer 的推荐方法是将 materializer 作为隐式参数传递给 actor:

class SocketActor(val ticker: String)(implicit val mat: ActorMaterializer) extends Actor {
  implicit val sys = context.system
  // ...
}

那你可以把主程序中的materializer传给这个actor:

object AkkaQuickstart extends App {

  implicit val system: ActorSystem = ActorSystem("test")
  implicit val materializer: ActorMaterializer = ActorMaterializer()

  val socketActor: ActorRef =
    system.actorOf(Props(classOf[SocketActor], "hello", materializer), "socket-actor")

  socketActor ! Start
}