1

我想减少绑定这些 akka 演员所需的样板文件。

目前,我的代码如下所示:

bind(classOf[ActorRef]).
  annotatedWith(Names.named("mines")).
  toProvider(new TypeLiteral[ActorProvider[MyActor]]() {}).
  asEagerSingleton()

我也希望它看起来像:

bindActor[MyActor].withName("mines")

我试图子类化AbstractModule以挤压这个概念,但无济于事。

相关代码:

class ActorProvider[T <: Actor] @Inject() ( val key:Key[T], val injector:Injector, val system: ActorSystem ) extends Provider[ActorRef] {
  def get = {
    system.actorOf(Props(injector.getInstance(key)))
  }
}
4

2 回答 2

1

查看https://github.com/codingwell/scala-guice/。这是一个基于它的示例。它允许

bindActor[MyActor].withName("mines")

请记住,您绑定的是非泛型 ActorRef 而不是 Actor 本身。这将为@Named("foo") ActorRef 创建一个绑定。你永远不应该直接使用 Actor。

您无法在提供程序中获取密钥。提供者不会像您尝试使用密钥或注入点那样进行任何上下文注入。你可以做的是为每个actor绑定创建一个不同的提供者实例,然后用 ActorSystem 注入它。或者,您也可以更改 API 以包含参与者系统实例。

trait AkkaModule extends AbstractModule {
  // should be:
  // this: AbstractModule =>
  // see http://lampsvn.epfl.ch/trac/scala/ticket/3564
  import ScalaModule._

  private def binderAccess = super.binder // shouldn't need super

  def bindActor[T <: Actor](implicit m: Manifest[T]) = new ActorBindingBuilder {
    //Hack, no easy way to exclude the bind method that gets added to classes inheriting ScalaModule
    //So we experamentally figured out how many calls up is the source, so we use that
    //Commit 52c2e92f8f6131e4a9ea473f58be3e32cd172ce6 has better class exclusion
    val mybinder = binderAccess.withSource((new Throwable).getStackTrace()(3))
    val self = (mybinder bind classOf[ActorRef]).asInstanceOf[AnnotatedBindingBuilder[ActorRef]]
  }

}

object AkkaModule {

  class ActorProvider(val name: String) extends Provider[ActorRef] {
    @Inject var system: ActorSystem = _
    def get = {
      system.actorFor(system.name + "/user/" + name)
    }
  }

  trait ActorBindingBuilder {
    val mybinder: Binder
    val self: AnnotatedBindingBuilder[ActorRef]

    def withName(name: String) = {
      val provider = new ActorProvider(name)
      self.annotatedWith(Names.named(name)).toProvider(provider)
      mybinder.requestInjection(provider)
    }
  }
}
于 2012-12-19T06:58:47.083 回答
0

像这样利用 scala 类型 Manifest 的东西可能会起作用 http://www.scala-lang.org/api/current/scala/reflect/Manifest.html 其中 Foo 类似于 ActorRef 而 Bla 类似于 MyActor:


scala> import com.google.inject
import com.google.inject

scala> val binder:inject.Binder = null
binder: com.google.inject.Binder = null

scala> class Foo {}
defined class Foo

scala> class Bla extends Foo {}
defined class Bla

scala> def bind[T <: Foo:Manifest] = binder.bind( classOf[Foo] ).toProvider( new
 inject.TypeLiteral[inject.Provider[T]](){} ).asEagerSingleton
bind: [T <: Foo](implicit evidence$1: Manifest[T])Unit

也许将其与隐式转换结合起来,将 Binder 转换为 MyBinder: http ://daily-scala.blogspot.com/2009/08/implicit-methods.html


class MyBinder {
    def bindActor[T <: ActorRef:Manifest]( nameToBind:String ):Unit = ...
}


object MyBinder {
    implicit def binderToMyBinder( ...
}

祝你好运!

于 2012-12-18T19:11:03.137 回答