我目前正在探索在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整合有一些指示?
答案 0 :(得分:4)
您提到过,您正在使用随附的object
作为服务。我也注意到,你是
在object
内创建演员。一般来说,我会劝阻你这样做。 Scala(同伴)object
s
只是单身人士。虽然它们在某些情况下可能是有用和适当的,但通常认为它们是有用的
反模式而不是模式,特别是如果你想进行依赖注入或控制反转
你的申请。这有很多原因,但在这种情况下最重要的原因是:它很难嘲笑它们,
它很难控制它们的实例化,并且通常它们代表了控制反转的反面。
另一个问题是,你是在这些单例对象中创建actor。演员模型的非常重要的方面是
supervision hierarchy。通过创建这个演员
(在你的案例中UserService
孤立地,你很可能让守护演员成为它的主管,在大多数情况下
不是你想要的。所以我建议在其他演员中创造大多数演员,除了少数,
需要成为顶级演员。这将确保他们有适当的监督层级。
如果您使用Scaldi,这些想法也会保持不变。 scaldi-akka提供
为某个特定演员注入ActorRef
或Props
的便捷方式。这是一个如何做的小例子
注入普通绑定和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
}
将Actor
与toProvider
绑定很重要。这将确保每次Akka向Scaldi询问一些
特别是Actor
,它将始终获得它的新实例。
现在,如果你希望ReceptionistService
成为你的顶级演员,你可以像这样使用它:
implicit val system = inject [ActorSystem]
val receptionist = injectActorRef [ReceptionistService]
receptionist ! DoStuff
在这种情况下,system
的监护人将是它的主管。