caeus
caeus

Reputation: 3716

How to plug into the play lifecycle with a module instead of a Plugin?

I see the Plugin class is now deprecated (as of 2.4.x version of play)... In the api documentation it says I should use modules instead... so that's my question. How do I write a module, and how do I plug that module into the play lifecycle of the main app?

Upvotes: 3

Views: 1084

Answers (1)

Steve Chaloner
Steve Chaloner

Reputation: 8202

You don't specify which language you're using, so I'll quickly cover both. I'm basing both answers on the following repositories:

Java

  1. Write your functionality any way you want - there are no specific classes to extend. If you have dependencies on Play components such as Configuration, you should inject them.

    @Singleton
    public class MyModuleCode {
    
        private final boolean enableWidgets;
    
        @javax.inject.Inject
        public MyModuleCode(final Configuration configuration) {
            this.enableWidgets = configuration.getBoolean("widgets.enabled", false);
        }
    }
    

Note that dependency injection is used in place of static reference. Also, note that I've given this example a @Singleton annotation, but it's also possible to have, for example, per-request scope.

See the Play DI docs for more information

  1. Expose the components of your module. To do this, extend the play.api.inject.Module class and implement public Seq<Binding<?>> bindings(final Environment environment, final Configuration configuration).

    package com.example.module;
    
    public class MyModule extends Module
    {
        @Override
        public Seq<Binding<?>> bindings(final Environment environment,
                                        final Configuration configuration)
        {
            return seq(bind(MyModuleCode.class).toSelf().in(Singleton.class));
        }
    }
    

Here, you can also bind implementations to interfaces, configure instance providers and so on.

  1. If it's something you're publicly releasing the module, let's assume you do this here - it's out of scope of the question. Let's also assume you've added a dependency for the module in whichever project you're working on.

  2. Enable the module in application.conf.

    play {
        modules {
            enabled += com.example.module.MyModule
        }
    }
    
  3. The components exposed via your module - just MyModuleCode in this example - is now available for injection into your controllers, actions, etc.

  4. If you need a shutdown hook, just inject ApplicationLifecycle into the component and register the hook; see https://playframework.com/documentation/2.4.x/JavaDependencyInjection#Stopping/cleaning-up for details.

Scala

  1. Write your functionality any way you want - there are no specific classes to extend. If you have dependencies on Play components such as CacheApi, you should inject them.

    @Singleton
    class DefaultPatternCache @Inject() (cache: CacheApi) extends PatternCache {
        override def apply(value: String): Option[Pattern] = cache.getOrElse[Option[Pattern]](key = s"Deadbolt.pattern.$value") { Some(Pattern.compile(value)) }
    }
    

Note that dependency injection is used in place of static reference. Also, note that I've given this example a @Singleton annotation, but it's also possible to have, for example, per-request scope.

See the Play DI docs for more information

  1. Expose the components of your module. To do this, extend the play.api.inject.Module class and implement def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]].

    package com.example.module
    
    import com.example.module.cache.{DefaultPatternCache, PatternCache}
    import play.api.inject.{Binding, Module}
    import play.api.{Configuration, Environment}
    
    class MyModule extends Module {
        override def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]] = Seq(bind[PatternCache].to[DefaultPatternCache])
    }
    

Here, you can also bind implementations to traits, configure instance providers and so on.

  1. If it's something you're publicly releasing the module, let's assume you do this here - it's out of scope of the question. Let's also assume you've added a dependency for the module in whichever project you're working on.

  2. Enable the module in application.conf.

    play {
        modules {
            enabled += com.example.module.MyModule
        }
    }
    
  3. The components exposed via your module - just MyModuleCode in this example - is now available for injection into your controllers, actions, etc.

  4. If you need a shutdown hook, just inject ApplicationLifecycle into the component and register the hook; see https://playframework.com/documentation/2.4.x/ScalaDependencyInjection#Stopping/cleaning-up for details.

Summary

Modules are no longer anything special - they're just a way of grouping injectable components.

Upvotes: 3

Related Questions