§Writing Play Modules
Note: This page covers the new module system to add functionality to Play.
The deprecated
play.api.Plugin
system is removed as of 2.5.x.
A module can be written using any dependency injection framework. However, when you want to extend Play, you need to avoid dependencies on a specific framework so that your extension can work independently of the dependency injection. Play previously used the play.api.Plugin
system for this purpose, but in 2.5.x, Plugins have been replaced with Play modules.
A Play module is a class that extends play.api.inject.Module
and can be registered with Play without relying explicitly on a particular dependency injection framework. This allows everyone to use Play modules.
A list of Play modules are available in the module directory.
In addition, because Play uses Play modules for built-in functionality, a Play module must be used to replace or augment built-in functionality.
§Creating and migrating Play modules
Creating a Play module is simple:
class MyCode {
// add functionality here
}
class MyModule extends play.api.inject.Module {
def bindings(environment: Environment, configuration: Configuration) = {
Seq(bind[MyCode].toInstance(new MyCode))
}
}
For more information, see the “Create a Module class” section of Plugins to Modules.
§Module Registration
Play modules are registered through Play’s configuration system by adding the Play module into reference.conf
:
play.modules.enabled += "modules.MyModule"
Please see migration page and the dependency injection documentation for more details.
§Application Lifecycle
A module can detect when Play shutdown occurs by injecting the [play.api.inject.ApplicationLifecycle
]((api/scala/play/api/inject/ApplicationLifecycle.html) trait into the singleton instance and adding a shutdown hook.
Please see the `ApplicationLifecycle` example and ApplicationLifecycle reference for more details.
§Testing Play Modules
Modules can be tested using Play’s built in test functionality, using the GuiceApplicationBuilder
and adding a binding to the module.
val application = new GuiceApplicationBuilder()
.bindings(new MyModule)
.build()
val myCode = application.injector.instanceOf(classOf[MyCode])
myCode must beAnInstanceOf[MyCode]
Please see Testing with Guice functionality is implemented by the MessagesApi trait and backed by DefaultMessagesApi. If you write a replacement class MyMessagesApi
that extends MessagesApi
, you can bind it with:
class MyI18nModule extends play.api.inject.Module {
def bindings(environment: Environment, configuration: Configuration) = {
Seq(
bind[Langs].to[DefaultLangs],
bind[MessagesApi].to[MyMessagesApi]
)
}
}
§Testing Overrides
Testing the application should be done using the overrides
method to replace the existing implementation:
val application = new GuiceApplicationBuilder()
.overrides(new MyI18nModule)
.build()
§Registration Overrides
Because the I18nModule
is loaded automatically in reference.conf
, you must first disable the default module before adding the replacement module:
play.modules.disabled += "play.api.i18n.I18nModule"
play.modules.enabled += "modules.MyI18nModule"
You should not disable existing modules in reference.conf
when publishing a Play module, as it may have unexpected consequences. Please see the migration page for details.