Scala+Akka多Actor向死信通道发消息的两类问题求助
Hey there! Let's break down and fix the two problems you're facing with your Scala/Akka actor setup step by step:
1. Compile Error: Cannot Resolve Symbol "!"
What's Going Wrong
Your DeviceManager is inheriting from ActorRef instead of Akka's core Actor trait, and you're holding a direct instance of DeadLetterChannel instead of its ActorRef. The ! (tell) method is only available on ActorRef instances (the "handle" to an actor), not on raw actor class instances — that's why you're hitting the compile error.
Fixed DeviceManager Code
Adjust DeviceManager to extend Actor and accept a DeadLetterChannel's ActorRef as a parameter:
import akka.actor.{Actor, ActorRef} class DeviceManager(val dlc: ActorRef) extends Actor { override def receive: Receive = { case Heartbeat => // Handle Heartbeat logic here... case Connect => // Handle Connect logic here... case Disconnect => // Handle Disconnect logic here... case unknownMsg => // Send the unhandled message to the dead letter channel dlc ! unknownMsg } }
2. Sending Unknown Messages to DeadLetterChannel
What's Going Wrong
In your original code, you had case _ => dlc ! ??? — you just need to capture the unhandled message and send it directly. Also, your DeadLetterChannel has a bug in its log statement: the ${} placeholder is empty, so it won't display the message type correctly.
Fixed DeadLetterChannel Code
import akka.actor.Actor import akka.event.Logging import scala.collection.mutable.Queue class DeadLetterChannel(val queue: mutable.Queue[Any]) extends Actor with Logging { override def receive: Receive = { case anyMsg: Any => log.info(s"${this.getClass.getSimpleName} received a message of type ${anyMsg.getClass.getSimpleName} from ${sender().path.name}.") queue.enqueue(anyMsg) // Note: The `case _` branch is redundant here — `Any` covers every possible message in Scala // case _ => log.warn(s"${this.getClass.getSimpleName} received a non-Any message.") } }
Key Notes
- In
DeviceManager's default case, we usecase unknownMsg =>to capture the unhandled message, then send it to the dead letter channel withdlc ! unknownMsg. - Fixed the log statement in
DeadLetterChannelto show the actual message type usinganyMsg.getClass.getSimpleName, and usedsender().path.namefor a more readable sender identifier. - Removed the redundant
case _branch becausecase anyMsg: Anyalready matches every possible message (there's no such thing as a "non-Any" message in Scala).
Quick Setup Example
When spawning your actors, create the DeadLetterChannel first, then pass its ActorRef to DeviceManager:
import akka.actor.ActorSystem import scala.collection.mutable val system = ActorSystem("DeviceNetworkSystem") val deadLetterQueue = mutable.Queue[Any]() val deadLetterChannelRef = system.actorOf(akka.actor.Props(new DeadLetterChannel(deadLetterQueue)), "dead-letter-channel") val deviceManagerRef = system.actorOf(akka.actor.Props(new DeviceManager(deadLetterChannelRef)), "device-manager")
内容的提问来源于stack exchange,提问作者hotmeatballsoup

