I am using Scala + Play and the out of box Guice set up for dependency injection. I am also using Akka Persistence behind the scenes and would like to create a binding for a custom read journal that I can then inject around my application.
Unfortunately, the read journal constructor (which I do not control) requires an explicit reference to the actor system:
PersistenceQuery(actorSystem).readJournalFor[CustomReadJournal]("custom-key")
How do I get a reference to the underlying actorSystem from within a binding definition class (Module)? Is this possible? More generally, is it possible to define interdependent bindings (a la Scaldi?)
My Module class entry currently looks like:
bind(classOf[CustomReadJournal]).toInstance(PersistenceQuery(<what do i put here?>).readJournalFor[CustomReadJournal]("custom-journal"))
Thanks in advance for the help!
If you need to do some kind of logic to create a dependency injection it is useful to use the #Provides annotation. For example:
trait MyProvider {
#Provides
def provideThing(): Thing = {
//make the thing and return it
}
}
class MyModule extends AbstractModule with MyProvider {
override def configure() {
bind(classOf[TraitYYY]).to(classOf[ClassThatTakesThingAsParameter])
}
}
A useful thing to know is that #Provides methods can themselves take parameters and get their arguments injected. For example:
#Provides
def provideThingNeedingParameter(param: P): ThingNeedingParam = {
new ThingNeedingParam(param)
}
Which is relevant to your situation I believe since you want to provide an actor system to an instance of some class.
// You can use #Singleton with #Provides if you need this to be one as well!
#Provides
def provideActorSystem(app: Application): ActorSystem = {
play.api.libs.concurrent.Akka.system(app)
}
#Provides
def providePersistenceQuery(actorSystem: ActorSystem): PersistenceQuery = {
PersistenceQuery(actorSystem)
}
#Provides
def provideCustomReadJournal(persistenceQuery: PersistenceQuery):CustomReadJournal = {
persistenceQuery.readJournalFor[CustomReadJournal]("custom-key")
}
By creating an #Provides annotated method for your CustomReadJournal you can avoid the bind call from configure entirely and control the parameters a bit more. Also, if you need to, #Provides works with #Singleton. I haven't used Akka persistence, but I think this should help you
Related
Is it possible to instantiate the dependency first and then bind it in the module config method?
Currently I have the following config:
class PersonServiceImpl #Inject()(addressService: AddressService) {
...
}
class AppModule extends AbstractModule with ScalaModule {
def configure() {
bind[PersonService].to[PersonServiceImpl]
bind[AddressBook].to[AddressBookImpl]
}
#Provides #Singleton
def provideAddressService(addressBook: AddressBook): AddressService = {
new AddressServiceImpl(addressBook) with SecureAddressView
}
}
... which works fine. What I want to do now is to move the instantiation of the AddressServiceImpl into a separate module. So, the problem is that in order to create an instance of AddressServiceImpl I need Guice to inject the addressBook parameter for me, but I also want to create the instance myself so I can mix SecureAddressView in:
class AddressModule extends AbstractModule with ScalaModule {
def configure() {
bind[AddressService].to[AddressServiceImpl]
}
#Provides #Singleton
def provideAddressService(addressBook: AddressBook): AddressService = {
new AddressServiceImpl(addressBook) with SecureAddressView
}
}
This fails, though, as Guice comes back complaining about the provideAddressService method. It basically says that A binding to AddressService was already configured and points to the bind[AddressService].to[AddressServiceImpl] line in the configure method.
Any idea how to create an instance and mix in a trait while still delegating the resolution of downstream parameter dependencies to Guice?
OK, quite an obvious one but I was misled by the fact that I had to override the configure method. So, all I had to do is provide a dummy implementation for configure.
class AddressModule extends AbstractModule with ScalaModule {
override def configure(): Unit = ()
#Provides #Singleton
def provideAddressService(addressBook: AddressBook): AddressService = {
new AddressServiceImpl(addressBook) with SecureAddressView
}
}
Although this still looks quite dodgy as I have to provide explicitly all the parameters to the AddressService constructor. There must be a more elegant way of mixin traits. Or maybe not...
I would like implement a Guice module which binds an adapter to a named argument, but to create this adapter, it needs to instantiate another class, which also need injected arguments.
Here is the example in Scala:
trait Service
class UserService #Inject()(#Named(value = "foo") foo: String) extends Service
trait Adapter
class AdapterImpl(service: Service) extends Adapter
class AdapterRef(val adapter: Adapter)
class Module extends AbstractModule {
override def configure(): Unit = {
val fooValue = "bar"
bind(classOf[String])
.annotatedWith(Names.named("foo"))
.toInstance(fooValue)
val userService = new UserService(fooValue) //It should be instantiated by Guice somehow
bind(classOf[AdapterRef])
.annotatedWith(Names.named("userService"))
.toInstance(new AdapterRef(new AdapterImpl(userService))) //Thats kinda ok
}
}
Can someone point me to the right direction?
Thank you,
Gabor
You can use a Provides method within your module, which lets you remove the binding. This is my best effort at Scala so if the syntax is incorrect let me know.
#Provides() #Singleton() def provideAdapterRef(service: Service): AdapterRef = {
return new AdapterRef(new AdapterImpl(service))
}
Note the use of Singleton to imitate your examples use of toInstance. If you don't need it to always provide the same instance I would recommend removing the scope and letting it create a new one every time.
An alternative solution is to use a Provider. This requires you to keep a modified version of the binding in your module and create an extra class, but it can be a cleaner solution if your Provider is more complex.
//Can inject UserService as well, or provide annotations to configure which
//implementation of Service you get if you have more than one.
class UserServiceProvider #Inject()(service: Service) extends Provider[AdapterRef] {
override def get(): AdapterRef {
return new AdapterRef(new AdapterImpl(service))
}
}
Then you can change your binding in the module to
bind(classOf[AdapterRef])
.annotatedWith(Names.named("userService"))
.toProvider(classOf[UserServiceProvider])
.in(classOf[Singleton])
Here note the use of in(Singleton) to replicate your toInstance behavior.
I'm working on Playframework2.5 with play-slick and programs related to it such as batch.
current project structure is like
/rootPlayProject
/app
/controllers
/filters
/services
...
Modules
/core (sub-project - DAOs,services are placed here)
/batch (sub-project depends on core)
I'm using Guice DI almost everywhere include Database Access Object(DAO).
And interfaces in core are bound in Module placed in core which end up getting inherited by Module in root project.
Core Module(/rootPlayProject/core/CoreModule.scala)
class CoreModule extends AbstractModule {
override def configure() = {
bind(classOf[FooDAO]).to(classOf[FooDAOImpl])
....
}
}
Root Module(/rootPlayProject/Modules.scala)
class Module extends CoreModule {
override def configure() = {
super.configure()
bind(classOf[FooService]).to(classOf[FooServiceImpl])
}
}
This works pretty well as Playframework application though, I would like to use core module for batch programs and I would like to run the batches without playframework.
so far I tried something like this
object BatchA {
def main(args: Array[String]) = {
val injector = Guice.createInjector(new CoreModule)
val foo = injector.getInstance(classOf[FooDAO])
//do something with foo.
}
}
but since my DAO's requiring things Playframework create such as ExecutionContext,play.api.db.slick.DatabaseConfigProvider and #play.db.NamedDatabase, above code does not run.
My question is, How can I let those things get bound without play application builder?
Thanks in advance.
The answer depends on whether or not you want to actually decouple Play Framework from your DAOs.
Option 1: Don't Decouple
Your main method could simply have the following lines preceeding your val injector line:
val application = new GuiceApplicationBuilder()
.in(Environment(new File("."), this.getClass.getClassLoader, Mode.Prod))
.build
Play.start(application)
Option 2: Decouple
Or, you can provide injectable classes that can provide the ExecutionContext specific to the environment. If you want to inject the DatabaseConfigProvider, you will have to perform further abstractions to remove the direct dependency on Play. The annotation will follow the Play-specific implementation of the abstraction.
In the case of my own project where I encountered this scenario, I opted for Option 1, as the dependency on Play wasn't severe enough of an impact for me.
GuiceInjectorBuilder do the trick.
trait PlayInjector {
lazy val injector = new GuiceInjectorBuilder().configure(Configuration.load(Environment.simple(mode = Mode.Dev)))
.bindings(new BuiltinModule, new CoreModule, new SlickModule).disable(classOf[Application]).injector
def closeInjector = injector.instanceOf[DefaultApplicationLifecycle].stop
}
BuiltinModule binds Play basic modules such as ExecutionContext, ExecutionContextExecutor or ActorSystem.
You can make your own Module to bind only things you need to though, using BuiltinModule and disable classes you don't need is simpler.
how to use it
object Foo extends PlayInjector {
def main(args: Array[String]) = {
val foo = injector.instanceOf[FooDAO]
val bar = injector.instanceOf[BarDAO]
//do something
//when you finish things you want to do
closeInjector
}
}
Since some modules like PlaySlick uses ApplicationLifecycle.addStopHook to handle closing operation. It's safer to execute them instead of just call sys.exit()
I'm trying to migrate from Play 2.4 to 2.5 avoiding deprecated stuff.
I had an abstract class Microservice from which I created some objects. Some functions of the Microservice class used play.api.libs.ws.WS to make HTTP requests and also play.Play.application.configuration to read the configuration.
Previously, all I needed was some imports like:
import play.api.libs.ws._
import play.api.Play.current
import play.api.libs.concurrent.Execution.Implicits.defaultContext
But now you should use dependency injection to use WS and also to use access the current Play application.
I have something like this (shortened):
abstract class Microservice(serviceName: String) {
// ...
protected lazy val serviceURL: String = play.Play.application.configuration.getString(s"microservice.$serviceName.url")
// ...and functions using WS.url()...
}
An object looks something like this (shortened):
object HelloWorldService extends Microservice("helloWorld") {
// ...
}
Unfortunately I don't understand how I get all the stuff (WS, configuration, ExecutionContect) into the abstract class to make it work.
I tried to change it to:
abstract class Microservice #Inject() (serviceName: String, ws: WSClient, configuration: play.api.Configuration)(implicit context: scala.concurrent.ExecutionContext) {
// ...
}
But this doesn't solve the problem, because now I have to change the object too, and I can't figure out how.
I tried to turn the object into a #Singleton class, like:
#Singleton
class HelloWorldService #Inject() (implicit ec: scala.concurrent.ExecutionContext) extends Microservice ("helloWorld", ws: WSClient, configuration: play.api.Configuration) { /* ... */ }
I tried all sorts of combinations, but I'm not getting anywhere and I feel I'm not really on the right track here.
Any ideas how I can use things like WS the proper way (not using deprecated methods) without making things so complicated?
This is more related to how Guice handles inheritance and you have to do exactly what you would do if you were not using Guice, which is declaring the parameters to the superclass and calling the super constructor at your child classes. Guice even suggest it at its docs:
Wherever possible, use constructor injection to create immutable objects. Immutable objects are simple, shareable, and can be composed.
Constructor injection has some limitations:
Subclasses must call super() with all dependencies. This makes constructor injection cumbersome, especially as the injected base class changes.
In pure Java, it will means doing something like this:
public abstract class Base {
private final Dependency dep;
public Base(Dependency dep) {
this.dep = dep;
}
}
public class Child extends Base {
private final AnotherDependency anotherDep;
public Child(Dependency dep, AnotherDependency anotherDep) {
super(dep); // guaranteeing that fields at superclass will be properly configured
this.anotherDep = anotherDep;
}
}
Dependency injection won't change that and you will just have to add the annotations to indicate how to inject the dependencies. In this case, since Base class is abstract, and then no instances of Base can be created, we may skip it and just annotate Child class:
public abstract class Base {
private final Dependency dep;
public Base(Dependency dep) {
this.dep = dep;
}
}
public class Child extends Base {
private final AnotherDependency anotherDep;
#Inject
public Child(Dependency dep, AnotherDependency anotherDep) {
super(dep); // guaranteeing that fields at superclass will be properly configured
this.anotherDep = anotherDep;
}
}
Translating to Scala, we will have something like this:
abstract class Base(dep: Dependency) {
// something else
}
class Child #Inject() (anotherDep: AnotherDependency, dep: Dependency) extends Base(dep) {
// something else
}
Now, we can rewrite your code to use this knowledge and avoid deprecated APIs:
abstract class Microservice(serviceName: String, configuration: Configuration, ws: WSClient) {
protected lazy val serviceURL: String = configuration.getString(s"microservice.$serviceName.url")
// ...and functions using the injected WSClient...
}
// a class instead of an object
// annotated as a Singleton
#Singleton
class HelloWorldService(configuration: Configuration, ws: WSClient)
extends Microservice("helloWorld", configuration, ws) {
// ...
}
The last point is the implicit ExecutionContext and here we have two options:
Use the default execution context, which will be play.api.libs.concurrent.Execution.Implicits.defaultContext
Use other thread pools
This depends on you, but you can easily inject an ActorSystem to lookup the dispatcher. If you decide to go with a custom thread pool, you can do something like this:
abstract class Microservice(serviceName: String, configuration: Configuration, ws: WSClient, actorSystem: ActorSystem) {
// this will be available here and at the subclass too
implicit val executionContext = actorSystem.dispatchers.lookup("my-context")
protected lazy val serviceURL: String = configuration.getString(s"microservice.$serviceName.url")
// ...and functions using the injected WSClient...
}
// a class instead of an object
// annotated as a Singleton
#Singleton
class HelloWorldService(configuration: Configuration, ws: WSClient, actorSystem: ActorSystem)
extends Microservice("helloWorld", configuration, ws, actorSystem) {
// ...
}
How to use HelloWorldService?
Now, there are two things you need to understand in order to proper inject an instance of HelloWorldService where you need it.
From where HelloWorldService gets its dependencies?
Guice docs has a good explanation about it:
Dependency Injection
Like the factory, dependency injection is just a design pattern. The core principle is to separate behaviour from dependency resolution.
The dependency injection pattern leads to code that's modular and testable, and Guice makes it easy to write. To use Guice, we first need to tell it how to map our interfaces to their implementations. This configuration is done in a Guice module, which is any Java class that implements the Module interface.
And then, Playframework declare modules for WSClient and for Configuration. Both modules gives Guice enough information about how to build these dependencies, and there are modules to describe how to build the dependencies necessary for WSClient and Configuration. Again, Guice docs has a good explanation about it:
With dependency injection, objects accept dependencies in their constructors. To construct an object, you first build its dependencies. But to build each dependency, you need its dependencies, and so on. So when you build an object, you really need to build an object graph.
In our case, for HelloWorldService, we are using constructor injection to enable Guice to set/create our object graph.
How HelloWorldService is injected?
Just like WSClient has a module to describe how an implementation is binded to an interface/trait, we can do the same for HelloWorldService. Play docs has a clear explanation about how to create and configure modules, so I won't repeat it here.
But after creating an module, to inject a HelloWorldService to your controller, you just declare it as a dependency:
class MyController #Inject() (service: Microservice) extends Controller {
def index = Action {
// access "service" here and do whatever you want
}
}
In scala,
-> If you do not want to explicitly forward all the injected parameters to the base constructor, you can do it like that :
abstract class Base {
val depOne: DependencyOne
val depTwo: DependencyTwo
// ...
}
case class Child #Inject() (param1: Int,
depOne: DependencyOne,
depTwo: DependencyTwo) extends Base {
// ...
}
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 objects as a services. I also noticed, that you are
creating actors inside of the objects. In general I will discourage you from doing this. Scala (companion) objects
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 or Props for some particular actor. Here is a small example of how you can
inject normal bindings and 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 = ???
}
Please note, that injectActorRef creates and actor within the context of current actor. So the equivalent would
be:
val userManager = context.actorOf(injectActorProps[UserService])
Now you need to create binding for the ActorSystem (it's optional, and if you are using Play, you probably
need to get ActorSystem from the play application, which already has one), services (which are actors in your case)
and managers:
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
}
It is important to bind Actors with toProvider. This will make sure, that each time Akka asks Scaldi for some
particular Actor, 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:
implicit val system = inject [ActorSystem]
val receptionist = injectActorRef [ReceptionistService]
receptionist ! DoStuff
In this case, systems guardian actor would be it's supervisor.