I'm currently exploring using Scaldi for Dependency Injection in a Play2.2 application.
I have read the documentation on Scaldi's website, but what is unclear to me is how to use it with Akka.
What I have so far in my project:
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..
In UserService.scala I would use an instance of the UserManager to do the work:
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))))
}
Then depending on the injected manager, the actor can be sort of mocked if it delegate all the work to the manager?
However, what if the managers needs to call other Services, which are just companion objects? Or Services calling other services that are also referenced via companion objects?
Does anyone have some pointers on how to integrate Akka with Scaldi?
You mentioned, that you are using companion
object
s as a services. I also noticed, that you are creating actors inside of theobject
s. In general I will discourage you from doing this. Scala (companion)object
s are just singletons. While they can be useful and appropriate in some circumstances, in general they are considered to be an anti-pattern rather than a pattern, especially if you want to do dependency injection or inversion of control in your application. There are a lot of reasons for this, but the most important ones in this case are: it's hard to mock them, it's hard to control their instantiation, and in general they represent an opposite of inversion of control.Another problem, is that you are creating actors inside of these singleton objects. Very important aspect of actor model is supervision hierarchy. By creating this actor (
UserService
in your case) in isolation, you most probably let guardian actor to be it's supervisor, which in most case is not what you want. So I would recommend to create most of the actors within another actors, except few, that need to be top-level actors. This will make sure that they have proper supervision hierarchy.These ideas also remain the same if you are using Scaldi. scaldi-akka provides convenient way to inject an
ActorRef
orProps
for some particular actor. Here is a small example of how you can inject normal bindings andActorRefs
:Please note, that
injectActorRef
creates and actor within the context of current actor. So the equivalent would be:Now you need to create binding for the
ActorSystem
(it's optional, and if you are using Play, you probably need to getActorSystem
from the play application, which already has one), services (which are actors in your case) and managers:It is important to bind
Actor
s withtoProvider
. This will make sure, that each time Akka asks Scaldi for some particularActor
, it will always get the new instance of it.Now, if you want
ReceptionistService
to be your top-level actor, you can use it like this:In this case,
system
s guardian actor would be it's supervisor.