문제

Recently I was switching from scala actors to akka actors, but noticed that akka actors use ActorRef instead of the instance object:

val actorRef: ActorRef = Actor.actorOf(new MyActor)

So I tried:

val myActor = new MyActor
val actorRef: ActorRef = Actor.actorOf(x)

... to have both: 1) ActorRef to send messages and 2) MyActor to call methods on.
But I got:

akka.actor.ActorInitializationException: ActorRef for instance of actor [MyActor] is not in scope.

So my question is: How can I obtain an instance (of some type) on which I can call ActorRef-like methods like ! AND also methods from the MyActor instance?

도움이 되었습니까?

해결책

What you're doing is a terrible idea. So just stop right now, step away from the keyboard, and go to the Akka Documentation and read up on Actors.

Consider this:

class YourActor extends Actor {
  var mutableStuff = ...
  def receive = {
    case _ =>
      // mess with mutableStuff
  }
  def publicMethod = // mess with mutableStuff
}

Now, set up your system and start sending messages and calling that method from other threads. Boom!

You're doing precisely what Akka and the Actor model help you prevent. You're actually bending over backwards to break what they've already fixed :) They won't let you do it.

Now, you can unit test by accessing methods directly but you need a TestActorRef for that. While you're reading the docs, read through the section on Testing.

다른 팁

The best that I can up with is the following, quite dirty:
Is there a better way?

import akka.actor._

trait ActorCom {
  var actorRefForInitialization: ActorRef = _
  lazy val actorRef: ActorRef = actorRefForInitialization
  def ?(message: Any)(implicit channel: UntypedChannel = NullChannel, timeout: Actor.Timeout = Actor.defaultTimeout) = actorRef ? message
  def !(msg: Any)(implicit sender: UntypedChannel) = actorRef ! msg
  def start = actorRef.start
}

object AkkaActorFactory {
  def apply[A <: Actor](newInstance: => A with ActorCom): A with ActorCom = {
    var instance: Option[A with ActorCom] = None
    val actorRef = Actor.actorOf({
      instance = Some(newInstance)
      instance.get
    })
    instance.get.actorRefForInitialization = actorRef
    instance.get.actorRef // touch lazy val in ActorCom, to make it equal to actorRef and then its fixed (immutable)
    instance.get
  }
}

class MyActor extends Actor {
  def receive = {
    case "test1" => println("good")
    case "test2" => println("fine")
    case _       => println("bad")
  }
  def sendTestMsg2Myself = self ! "test2"
}

val myActor = AkkaActorFactory(newInstance = new MyActor with ActorCom)
myActor.start
myActor ! "test1"
myActor.sendTestMsg2Myself // example for calling methods on MyActor-instance
myActor ! PoisonPill
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top