Scaldi依赖注入和Akka Actors

时间:2014-03-02 07:15:18

标签: scala dependency-injection akka scaldi

我目前正在探索在Play2.2应用程序中使用Scaldi进行依赖注入。

我已阅读Scaldi网站上的文档,但我不清楚如何将其与Akka一起使用。

我目前在项目中的所作所为:

Models/ (Daos and case classes)
   User.scala
Services/  (Akka Actors)
   UserService.scala
   ProfileService.scala
Managers/  (Regular Manager Classes)
   UserManager.scala (The Trait Interface)
   UserManagerImpl.scala (An actual implementation)
   UserManagerMock.scala (Mocked version)
   etc..

在UserService.scala中,我将使用UserManager的一个实例来完成工作:

class UserService extends ServiceActor with Injection
{
    val userManager = inject[UserManager]

    def receive = {
        case Register(email: String, password: String)
    }
}

object UserService extends Service
{
    case class Register(email: String, password: String)

    override protected val actorRef = Akka.system.actorOf(Props[UserService].withRouter(SmallestMailboxRouter(resizer = Some(resizer))))
}

然后,根据注入的经理,如果将所有工作委托给经理,那么演员可能会被嘲笑?

但是,如果管理人员需要调用其他服务,这只是伴随对象,该怎么办?或服务调用其他服务也通过伴随对象引用?

有没有人对如何将Akka与Scaldi整合有一些指示?

1 个答案:

答案 0 :(得分:4)

您提到过,您正在使用随附的object作为服务。我也注意到,你是 在object内创建演员。一般来说,我会劝阻你这样做。 Scala(同伴)object s 只是单身人士。虽然它们在某些情况下可能是有用和适当的,但通常认为它们是有用的 反模式而不是模式,特别是如果你想进行依赖注入或控制反转 你的申请。这有很多原因,但在这种情况下最重要的原因是:它很难嘲笑它们, 它很难控制它们的实例化,并且通常它们代表了控制反转的反面。

另一个问题是,你是在这些单例对象中创建actor。演员模型的非常重要的方面是 supervision hierarchy。通过创建这个演员 (在你的案例中UserService孤立地,你很可能让守护演员成为它的主管,在大多数情况下 不是你想要的。所以我建议在其他演员中创造大多数演员,除了少数,  需要成为顶级演员。这将确保他们有适当的监督层级。

如果您使用Scaldi,这些想法也会保持不变。 scaldi-akka提供 为某个特定演员注入ActorRefProps的便捷方式。这是一个如何做的小例子 注入普通绑定和ActorRefs

class ProfileManager (implicit inj: Injector) extends Injectable

trait UserManager {
  def register(email: String, password: String): User
}

class UserManagerImpl(implicit inj: Injector) extends UserManager with Injectable {
  val profileManager = inject [ProfileManager]

  def register(email: String, password: String) = ???
}

class UserService(implicit inj: Injector) extends Actor with AkkaInjectable {
  val userManager = inject [UserManager]

  import UserService._

  def receive = {
    case Register(email, password) =>
      userManager
  }
}

object UserService {
  case class Register(email: String, password: String)
}

class ReceptionistService(implicit inj: Injector) extends Actor with AkkaInjectable {
  val userManager = injectActorRef [UserService]
  def receive = ???
}

请注意,injectActorRef在当前演员的上下文中创建和演员。所以相当于 是:

val userManager = context.actorOf(injectActorProps[UserService])

现在你需要为ActorSystem创建绑定(它是可选的,如果你使用Play,你可能 需要从播放应用程序(已经有一个),服务(在你的情况下是演员)获得ActorSystem 和经理:

implicit val module = new Module {
    bind [ActorSystem] to ActorSystem("MySystem")

    binding toProvider new UserService
    binding toProvider new ReceptionistService

    bind [UserManager] to new UserManagerImpl
    binding to new ProfileManager
}

ActortoProvider绑定很重要。这将确保每次Akka向Scaldi询问一些 特别是Actor,它将始终获得它的新实例。

现在,如果你希望ReceptionistService成为你的顶级演员,你可以像这样使用它:

implicit val system = inject [ActorSystem]

val receptionist = injectActorRef [ReceptionistService]

receptionist ! DoStuff

在这种情况下,system的监护人将是它的主管。