2012-12-18 3 views
1

Je voudrais réduire le temps nécessaire pour lier ces acteurs akka.Acteurs de Guice et Akka à Scala

Au cours, mon code ressemble à ceci:

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

J'aimerais paraître trop comme:

bindActor[MyActor].withName("mines") 

J'ai essayé de sous-classe AbstractModule pour presser ce concept pour pas profiter.

Code Pertinent:

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))) 
    } 
} 

Répondre

0

Quelque chose comme ce qui tire parti type de scala Manifest pourrait fonctionner http://www.scala-lang.org/api/current/scala/reflect/Manifest.html où Foo est analogue à ActorRef et Bla est analogue à 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 

Peut-être que co mbine que la conversion implicite pour convertir un classeur à un 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(... 
} 

Bonne chance!

1

Découvrez https://github.com/codingwell/scala-guice/. Voici un exemple basé dessus. Il permet

bindActor[MyActor].withName("mines") 

Gardez à l'esprit que vous liez un ActorRef non générique et non Acteur lui-même. Cela créera une liaison pour @Named ("foo") ActorRef. Vous ne devriez jamais travailler directement avec Actor.

Vous ne pouvez pas entrer de clé dans le fournisseur. Le fournisseur ne prend aucune injection contextuelle comme vous avez essayé avec la clé ou par ex. Point d'injection. Ce que vous pouvez faire est de créer une instance différente du fournisseur pour chaque liaison d'acteur et l'injecter avec ActorSystem par la suite. Vous pouvez également modifier l'API pour inclure l'instance du système d'acteur.

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) 
    } 
    } 
}