documentation/manual/working/scalaGuide/main/dependencyinjection/ScalaDependencyInjection.md
Dependency injection is a widely used design pattern that helps separate your components' behaviour from dependency resolution. Play supports both runtime dependency injection based on JSR 330 (described in this page) and [[compile time dependency injection|ScalaCompileTimeDependencyInjection]] in Scala.
Runtime dependency injection is so called because the dependency graph is created, wired and validated at runtime. If a dependency cannot be found for a particular component, you won't get an error until you run your application.
Play supports Guice out of the box, but other JSR 330 implementations can be plugged in. The Guice wiki is a great resource for learning more about the features of Guice and DI design patterns in general.
Play's sbt plugins do not provide any specific dependency injection framework by default. If you want to use Play's Guice module, add it explicitly to your library dependencies as follows:
libraryDependencies += guice
Note: Guice is a Java library and the examples in this documentation use Guice's built-in Java API. If you prefer a Scala DSL you might wish to use the scala-guice or sse-guice library.
Dependency injection achieves several goals:
The Guice wiki has some good examples explaining this in more detail.
Play provides a number of built-in components and declares them in modules such as its BuiltinModule. These bindings describe everything that's needed to create an instance of Application, including, by default, a router generated by the routes compiler that has your controllers injected into the constructor. These bindings can then be translated to work in Guice and other runtime DI frameworks.
The Play team maintains the Guice module, which provides a GuiceApplicationLoader. That does the binding conversion for Guice, creates the Guice injector with those bindings, and requests an Application instance from the injector.
There are also third-party loaders that do this for other frameworks, including Scaldi and Spring.
Alternatively, Play provides a BuiltInComponents trait that allows you to create a pure Scala implementation that wires together your app [[at compile time|ScalaCompileTimeDependencyInjection]].
We explain how to customize the default bindings and application loader in more detail below.
If you have a component, such as a controller, and it requires some other components as dependencies, then this can be declared using the @Inject annotation. The @Inject annotation can be used on fields or on constructors. We recommend that you use it on constructors, for example:
Note that the @Inject annotation must come after the class name but before the constructor parameters, and must have parentheses.
Also, Guice does come with several other types of injections, but constructor injection is generally the most clear, concise, and testable in Scala, so we recommend using it.
Guice is able to automatically instantiate any class with an @Inject on its constructor without having to explicitly bind it. This feature is called just in time bindings is described in more detail in the Guice documentation. If you need to do something more sophisticated you can declare a custom binding as described below.
Play's routes compiler generates a router class that declares your controllers as dependencies in the constructor. This allows your controllers to be injected into the router.
Prefixing the controller name with an @ symbol takes on a special meaning: instead of the controller being injected directly, a Provider of the controller will be injected. This allows, for example, prototype controllers, as well as an option for breaking cyclic dependencies.
The dependency injection system manages the lifecycle of injected components, creating them as needed and injecting them into other components. Here's how component lifecycle works:
close method. However, Play provides a special type of component, called the ApplicationLifecycle which lets you register components to shut down when the application stops.Sometimes you may have a component that holds some state, such as a cache, or a connection to an external resource, or a component might be expensive to create. In these cases it may be important that there is only be one instance of that component. This can be achieved using the @Singleton annotation:
Some components may need to be cleaned up when Play shuts down, for example, to stop thread pools. Play provides an ApplicationLifecycle component that can be used to register hooks to stop your component when Play shuts down:
The ApplicationLifecycle will stop all components in reverse order from when they were created. This means any components that you depend on can still safely be used in your component's stop hook. Because you depend on them, they must have been created before your component was, and therefore won't be stopped until after your component is stopped.
Note: It's very important to ensure that all components that register a stop hook are singletons. Any non singleton components that register stop hooks could potentially be a source of memory leaks, since a new stop hook will be registered each time the component is created.
You can can also implement the cleanup logic using [[Coordinated Shutdown|Shutdown]]. Play uses Pekko's Coordinated Shutdown internally but it is also available for userland code. ApplicationLifecycle#stop is implemented as a Coordinated Shutdown task. The main difference is that ApplicationLifecycle#stop runs all stop hooks sequentially in a predictable order where Coordinated Shutdown runs all tasks in the same phase in parallel which may be faster but unpredictable.
It is considered good practice to define a trait for a component, and have other classes depend on that trait, rather than the implementation of the component. By doing that, you can inject different implementations, for example you inject a mock implementation when testing your application.
In this case, the DI system needs to know which implementation should be bound to that trait. The way we recommend that you declare this depends on whether you are writing a Play application as an end user of Play, or if you are writing library that other Play applications will consume.
We recommend that Play applications use whatever mechanism is provided by the DI framework that the application is using. Although Play does provide a binding API, this API is somewhat limited, and will not allow you to take full advantage of the power of the framework you're using.
Since Play provides support for Guice out of the box, the examples below show how to provide bindings for Guice.
The simplest way to bind an implementation to an interface is to use the Guice @ImplementedBy annotation. For example:
In some more complex situations, you may want to provide more complex bindings, such as when you have multiple implementations of the one trait, which are qualified by @Named annotations. In these cases, you can implement a custom Guice Module:
If you call this module Module and place it in the root package, it will automatically be registered with Play. Alternatively, if you want to give it a different name or put it in a different package, you can register it with Play by appending its fully qualified class name to the play.modules.enabled list in application.conf:
play.modules.enabled += "modules.HelloModule"
You can also disable the automatic registration of a module named Module in the root package by adding it to the disabled modules:
play.modules.disabled += "Module"
Sometimes you might want to read the Play Configuration or use a ClassLoader when you configure Guice bindings. You can get access to these objects by adding them to your module's constructor.
In the example below, the Hello binding for each language is read from a configuration file. This allows new Hello bindings to be added by adding new settings in your application.conf file.
Note: In most cases, if you need to access
Configurationwhen you create a component, you should inject theConfigurationobject into the component itself or into the component'sProvider. Then you can read theConfigurationwhen you create the component. You usually don't need to readConfigurationwhen you create the bindings for the component.
In the code above, new EnglishHello and GermanHello objects will be created each time they are used. If you only want to create these objects once, perhaps because they're expensive to create, then you should use the @Singleton annotation. If you want to create them once and also create them eagerly when the application starts up, rather than lazily when they are needed, then you can Guice's eager singleton binding.
Eager singletons can be used to start up a service when an application starts. They are often combined with a shutdown hook so that the service can clean up its resources when the application stops.
It's important to note that the behavior of eager bindings differs between development and production modes:
sbt run):
sbt stage):
If you're implementing a library for Play, then you probably want it to be DI framework agnostic, so that your library will work out of the box regardless of which DI framework is being used in an application. For this reason, Play provides a lightweight binding API for providing bindings in a DI framework agnostic way.
To provide bindings, implement a Module to return a sequence of the bindings that you want to provide. The Module trait also provides a DSL for building bindings:
This module can be registered with Play automatically by appending it to the play.modules.enabled list in reference.conf:
play.modules.enabled += "com.example.HelloModule"
Module bindings method takes a Play Environment and Configuration. You can access these if you want to configure the bindings dynamically..eagerly at the end of your Binding.In order to maximize cross framework compatibility, keep in mind the following things:
If there is a module that you don't want to be loaded, you can exclude it by appending it to the play.modules.disabled property in application.conf:
play.modules.disabled += "play.api.db.evolutions.EvolutionsModule"
Circular dependencies happen when one of your components depends on another component that depends on the original component (either directly or indirectly). For example:
In this case, Foo depends on Bar, which depends on Baz, which depends on Foo. So you won't be able to instantiate any of these classes. You can work around this problem by using a Provider:
Generally, circular dependencies can be resolved by breaking up your components in a more atomic way, or finding a more specific component to depend on. A common problem is a dependency on Application. When your component depends on Application it's saying that it needs a complete application to do its job; typically that's not the case. Your dependencies should be on more specific components (e.g. Environment) that have the specific functionality you need. As a last resort you can work around the problem by injecting a Provider[Application].
Play's runtime dependency injection is bootstrapped by the GuiceApplicationLoader class. This class loads all the modules, feeds the modules into Guice, then uses Guice to create the application. If you want to control how Guice initializes the application then you can extend the GuiceApplicationLoader class.
There are several methods you can override, but you'll usually want to override the builder method. This method reads the ApplicationLoader.Context and creates a GuiceApplicationBuilder. Below you can see the standard implementation for builder, which you can change in any way you like. You can find out how to use the GuiceApplicationBuilder in the section about [[testing with Guice|ScalaTestingWithGuice]].
When you override the ApplicationLoader you need to tell Play. Add the following setting to your application.conf:
play.application.loader = "modules.CustomApplicationLoader"
You're not limited to using Guice for dependency injection. By overriding the ApplicationLoader you can take control of how the application is initialized. Find out more in the [[next section|ScalaCompileTimeDependencyInjection]].
Sometimes you may want to add new dependency to some base class which may have many subclasses. To avoid providing the dependency directly to each of them you may add it as an injectable field. This approach can reduce the testability of the class so use it with care.