简体   繁体   English

找不到ActorSystem的隐式值

[英]Could not find implicit value for ActorSystem

I'm just starting out with Akka and Scala and I'm trying to connect to a WebSocket using Akka Streams. 我刚开始使用Akka和Scala,并尝试使用Akka Streams连接到WebSocket。 I've created my SocketActor below and I try to instantiate from the main method. 我在下面创建了我的SocketActor ,然后尝试从main方法实例化。

Here is my SocketActor : 这是我的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()
  }
}

And my main method: 而我的主要方法是:

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
}

Unfortunately, I get the error: 不幸的是,我得到了错误:

Error:(38, 35) could not find implicit value for parameter system: akka.actor.ActorSystem private val webSocketFlow = Http().webSocketClientFlow(WebSocketRequest("wss://api.com/v1/")) 错误:(38,35)找不到参数系统的隐式值:akka.actor.ActorSystem私有val webSocketFlow = Http()。webSocketClientFlow(WebSocketRequest(“ wss://api.com/v1/”))

I've tried passing some implicit parameters to the constructor of the SocketActor but that didn't work too well. 我尝试将一些implicit参数传递给SocketActor的构造函数,但效果不太好。 It seems like the ActorSystem is not in scope for some reason. 似乎ActorSystem出于某种原因不在范围内。 How can I get my system in scope for the Http() function in SocketActor ? 如何在SocketActorHttp()函数范围内获得我的system

Define an implicit val : 定义一个隐式val

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

This will provide the implicit ActorSystem that the Http object expects. 这将提供Http对象期望的隐式ActorSystem

There is another issue with your code: the stream in your actor will not run because there is no materializer in scope. 您的代码还有另一个问题:由于范围中没有实现器,因此actor中的流将不会运行。 One way to address this is to create the materializer inside the actor: 解决此问题的一种方法是在actor中创建实现器:

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

Note that if the materializer were defined as implicit val mat = ActorMaterializer() , it would implicitly use context.system because of the implicit val sys = context.system . 请注意,如果materializer被定义为implicit val mat = ActorMaterializer()它会暗中使用context.system的,因为implicit val sys = context.system Instead, the materializer is created with the actor's context explicitly. 取而代之的是,物化器是使用参与者的context显式创建的。 This is done because of the warning in the documentation : 这样做是由于文档中的警告:

Do not create new actor materializers inside actors by passing the context.system to it. 不要通过将context.system传递给actor在actor中创建新的actor context.system This will cause a new ActorMaterializer to be created and potentially leaked (unless you shut it down explicitly) for each such actor. 这将导致为每个此类actor创建一个新的ActorMaterializer并可能泄漏(除非您明确将其关闭)。 It is instead recommended to either pass-in the Materializer or create one using the actor's context . 相反,建议您传入Materializer或使用actor的context创建一个。

The recommended approach, which allows the creator of the actor to reuse a materializer, is to pass the materializer to the actor as an implicit parameter: 推荐的方法允许actor的创建者重用物化器,该方法是将物化器作为隐式参数传递给actor:

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

Then you could pass the materializer in the main program to this 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
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM