3

我目前正在探索在 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 集成有一些指示吗?

4

1 回答 1

4

您提到过,您正在使用合作伙伴object作为服务。我还注意到,您正在objects 中创建演员。一般来说,我会劝阻你不要这样做。Scala (companion)object只是单例。虽然它们在某些情况下可能有用且合适,但通常它们被认为是反模式而不是模式,特别是如果您想在应用程序中进行依赖注入或控制反转。这有很多原因,但在这种情况下最重要的原因是:很难模拟它们,很难控制它们的实例化,并且通常它们代表了控制反转的对立面。

另一个问题是,您正在这些单例对象中创建演员。演员模型非常重要的方面是 监督层次结构。通过孤立地创建这个演员(UserService在你的情况下),你很可能让监护人演员成为它的监督者,这在大多数情况下不是你想要的。所以我建议在其他演员中创建大部分演员,除了少数需要顶级演员。这将确保它们具有适当的监督层次结构。

如果您使用 Scaldi,这些想法也保持不变。scaldi-akka提供了一种方便的方式来为某个特定的actor注入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从已经有一个的 play 应用程序)、服务(在您的情况下是参与者)和管理器创建绑定:

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
}

Actor将s 与绑定很重要toProvider。这将确保,每次 Akka 向 Scaldi 询问某个特定Actor的 时,它总是会获得它的新实例。

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

implicit val system = inject [ActorSystem]

val receptionist = injectActorRef [ReceptionistService]

receptionist ! DoStuff

在这种情况下,systems Guardian Actor 将是它的主管。

于 2014-03-03T22:42:56.793 回答