Skip to content

Commit

Permalink
Akka 2.6.0-M8, drop runtime DI support for class-based behaviors
Browse files Browse the repository at this point in the history
  • Loading branch information
dwijnand committed Oct 8, 2019
1 parent 07984ab commit afb7fab
Show file tree
Hide file tree
Showing 15 changed files with 103 additions and 85 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,14 @@

package play.libs.akka;

import scala.reflect.ClassTag;

import akka.actor.Actor;
import akka.actor.ActorRef;
import akka.actor.Props;
import akka.actor.typed.Behavior;
import akka.annotation.ApiMayChange;
import com.google.inject.assistedinject.FactoryModuleBuilder;
import com.google.inject.name.Names;
import com.google.inject.util.Providers;
import play.api.libs.concurrent.TypedActorRefProvider;
import play.libs.Akka;

import static play.api.libs.concurrent.TypedAkka.*;

import java.util.function.Function;

/**
Expand All @@ -36,7 +29,7 @@
* }
* </pre>
*
* Then to use the above actor in your application, add a qualified injected dependency, like so:
* <p>Then to use the above actor in your application, add a qualified injected dependency, like so:
*
* <pre>
* public class MyController extends Controller {
Expand Down Expand Up @@ -104,28 +97,4 @@ default <T extends Actor> void bindActorFactory(Class<T> actorClass, Class<?> fa
BinderAccessor.binder(this)
.install(new FactoryModuleBuilder().implement(Actor.class, actorClass).build(factoryClass));
}

/**
* Bind a typed actor.
*
* <p>For the given message type {@code T} binds {@code Behavior[T]} to the given {@link Behavior}
* subclass and {@code ActorRef[T]} to an instance of {@link TypedActorRefProvider} with the given
* actor name, so that it can be injected into other components.
*
* <p>Note that, while the name is used when spawning the actor in the {@code ActorSystem}, it is
* <em>NOT</em> used as a name qualifier for the binding. This is so that you don't need to use
* {@link javax.inject.Named Named} to qualify all injections of typed actors. Use the underlying
* API to create multiple, name-annotated bindings.
*
* @param behaviorClass The {@code Behavior} subclass for the typed actor.
* @param name The name of the typed actor.
* @param <T> The type of the messages the typed actor can handle.
*/
@ApiMayChange
default <T> void bindTypedActor(Class<? extends Behavior<T>> behaviorClass, String name) {
Class<T> cls = messageTypeOf(behaviorClass);
TypedActorRefProvider<T> provider = new TypedActorRefProvider<>(name, ClassTag.apply(cls));
BinderAccessor.binder(this).bind(behaviorOf(cls)).to(behaviorClass).asEagerSingleton();
BinderAccessor.binder(this).bind(actorRefOf(cls)).toProvider(provider).asEagerSingleton();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ trait AkkaGuiceSupport {
*
* Binds `Behavior[T]` and `ActorRef[T]` for the given message type `T` to the given [[Behavior]]
* value and actor name, so that it can be injected into other components. Use this variant of
* `bindTypedActor` when your actor's behavior doesn't depend on anything in dependency scope.
* `bindTypedActor` when using the "functional programming" style of defining your actor's
* behavior and it doesn't depend on anything in dependency scope.
*
* $unnamed
*
Expand Down Expand Up @@ -180,30 +181,6 @@ trait AkkaGuiceSupport {
bindTypedActorRef[T](name)
}

/**
* Bind a typed actor.
*
* Binds `Behavior[T]` and `ActorRef[T]` for the given message type `T` to the given [[Behavior]]
* subclass and actor name, so that it can be injected into other components. Use this variant of
* `bindTypedActor` when using the "object-oriented" style of defining your actor's behavior and
* (optionally) it needs to be injected with dependencies in dependency scope (such as
* [[play.api.Configuration Configuration]].
*
* The [[Behavior]] class passed will typically be an application-specific, named subclass of
* Akka's scaladsl [[akka.actor.typed.scaladsl.AbstractBehavior AbstractBehavior]].
*
* $unnamed
*
* @param behaviorClass The `Behavior` subclass for the typed actor.
* @param name The name of the typed actor.
* @tparam T The type of the messages the typed actor can handle.
*/
@ApiMayChange
final def bindTypedActor[T: ClassTag](behaviorClass: Class[_ <: Behavior[T]], name: String): Unit = {
accessBinder.bind(behaviorOf[T]).to(behaviorClass).asEagerSingleton()
bindTypedActorRef[T](name)
}

private[concurrent] final def bindTypedActorRef[T: ClassTag](name: String): Unit = {
accessBinder.bind(actorRefOf[T]).toProvider(new TypedActorRefProvider[T](name)).asEagerSingleton()
}
Expand Down
12 changes: 6 additions & 6 deletions documentation/manual/working/commonGuide/akka/AkkaTyped.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@

## Akka Actor Typed styles

Akka's [Typed Actor API][] has two styles:
Akka's [Actor Typed API][] has two styles:

1. a ["functional programming" style][fp-style], based on defining actor `Behavior` as values, and
2. a ["object-oriented" style][oo-style], based on defining the `Behavior` as a subclass
1. a ["functional programming" style][fp-style], based on defining an actor `Behavior`s with values, and
2. a ["object-oriented" style][oo-style], based on defining an actor `Behavior`s with subclasses.

[Typed Actor API]: https://doc.akka.io/docs/akka/2.6/typed/actors.html
[Actor Typed API]: https://doc.akka.io/docs/akka/2.6/typed/actors.html
[fp-style]: https://doc.akka.io/docs/akka/2.6/typed/actors.html#functional-style
[oo-style]: https://doc.akka.io/docs/akka/2.6/typed/actors.html#object-oriented-style

Expand Down Expand Up @@ -36,7 +36,7 @@ Java

## Compile-time dependency injection

Using compile-time dependency injection for Akka Typed requires creating the actor `Behavior` value and using it to spawn the actor:
Using compile-time dependency injection for Akka Actor Typed requires creating the actor `Behavior` value and using it to spawn the actor:

Scala
: @[compile-time-di](code/scalaguide/akka/typed/fp/AppComponents.scala)
Expand All @@ -56,7 +56,7 @@ Scala
Java
: @[main](code/javaguide/akka/typed/Main.java)

You can define a Guice `Module` defined like so:
You can define a Guice `Module` like so:

Scala FP
: @[fp-app-module](code/scalaguide/akka/typed/fp/AppModule.scala)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import akka.actor.ActorSystem;
import akka.actor.typed.ActorRef;
import akka.actor.typed.javadsl.Adapter;
import akka.actor.typed.javadsl.Behaviors;
import com.google.inject.AbstractModule;
import com.google.inject.TypeLiteral;
import com.google.inject.name.Names;
Expand Down Expand Up @@ -76,7 +77,8 @@ private void bindHelloActor(String name) {

@Override
public ActorRef<HelloActor.SayHello> get() {
return Adapter.spawn(actorSystem, new HelloActor(), name);
return Adapter.spawn(
actorSystem, Behaviors.setup(context -> new HelloActor(context)), name);
}
})
.asEagerSingleton();
Expand All @@ -92,7 +94,10 @@ private void bindConfiguredActor(String name) {

@Override
public ActorRef<ConfiguredActor.GetConfig> get() {
return Adapter.spawn(actorSystem, new ConfiguredActor(config), name);
return Adapter.spawn(
actorSystem,
Behaviors.setup(context -> new ConfiguredActor(context, config)),
name);
}
})
.asEagerSingleton();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
// #compile-time-di
import akka.actor.typed.ActorRef;
import akka.actor.typed.javadsl.Adapter;
import akka.actor.typed.javadsl.Behaviors;
import play.ApplicationLoader;
import play.BuiltInComponentsFromContext;
import play.mvc.EssentialFilter;
Expand All @@ -23,9 +24,13 @@ public final class AppComponents extends BuiltInComponentsFromContext {

public AppComponents(ApplicationLoader.Context context) {
super(context);
helloActor = Adapter.spawn(actorSystem(), new HelloActor(), "hello-actor");
helloActor =
Adapter.spawn(actorSystem(), Behaviors.setup(ctx -> new HelloActor(ctx)), "hello-actor");
configuredActor =
Adapter.spawn(actorSystem(), new ConfiguredActor(config()), "configured-actor");
Adapter.spawn(
actorSystem(),
Behaviors.setup(ctx -> new ConfiguredActor(ctx, config())),
"configured-actor");
main = new Main(helloActor, configuredActor);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,51 @@
package javaguide.akka.typed;

// #oo-app-module
import akka.actor.ActorSystem;
import akka.actor.typed.ActorRef;
import akka.actor.typed.javadsl.Adapter;
import akka.actor.typed.javadsl.Behaviors;
import com.google.inject.AbstractModule;
import play.libs.akka.AkkaGuiceSupport;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.typesafe.config.Config;
import javax.inject.Inject;
import play.api.Configuration;
import play.api.libs.concurrent.AkkaGuiceSupport;

public class AppModule extends AbstractModule implements AkkaGuiceSupport {
public class AppModule extends AbstractModule {

@Override
protected void configure() {
bindTypedActor(HelloActor.class, "hello-actor");
bindTypedActor(ConfiguredActor.class, "configured-actor");
bind(new TypeLiteral<ActorRef<HelloActor.SayHello>>() {})
.toProvider(
new Provider<ActorRef<HelloActor.SayHello>>() {
@Inject ActorSystem actorSystem;

@Override
public ActorRef<HelloActor.SayHello> get() {
return Adapter.spawn(
actorSystem,
Behaviors.setup(context -> new HelloActor(context)),
"hello-actor");
}
})
.asEagerSingleton();
bind(new TypeLiteral<ActorRef<ConfiguredActor.GetConfig>>() {})
.toProvider(
new Provider<ActorRef<ConfiguredActor.GetConfig>>() {
@Inject ActorSystem actorSystem;
@Inject Config config;

@Override
public ActorRef<ConfiguredActor.GetConfig> get() {
return Adapter.spawn(
actorSystem,
Behaviors.setup(context -> new ConfiguredActor(context, config)),
"configured-actor");
}
})
.asEagerSingleton();
}
}
// #oo-app-module
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
import akka.actor.typed.ActorRef;
import akka.actor.typed.Behavior;
import akka.actor.typed.javadsl.AbstractBehavior;
import akka.actor.typed.javadsl.Receive;
import akka.actor.typed.javadsl.ActorContext;
import akka.actor.typed.javadsl.Adapter;
import akka.actor.typed.javadsl.Receive;
import com.typesafe.config.Config;

import javax.inject.Inject;
Expand All @@ -26,8 +27,8 @@ public GetConfig(ActorRef<String> replyTo) {

private final String config;

@Inject
public ConfiguredActor(Config configuration) {
public ConfiguredActor(ActorContext<ConfiguredActor.GetConfig> context, Config configuration) {
super(context);
config = configuration.getString("my.config");
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import akka.actor.typed.ActorRef;
import akka.actor.typed.Behavior;
import akka.actor.typed.javadsl.AbstractBehavior;
import akka.actor.typed.javadsl.ActorContext;
import akka.actor.typed.javadsl.Receive;

public final class HelloActor extends AbstractBehavior<HelloActor.SayHello> {
Expand All @@ -22,6 +23,10 @@ public SayHello(String name, ActorRef<String> replyTo) {
}
}

public HelloActor(ActorContext<HelloActor.SayHello> context) {
super(context);
}

@Override
public Receive<SayHello> createReceive() {
return newReceiveBuilder().onMessage(SayHello.class, this::onHello).build();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@

package scalaguide.akka.typed

import akka.actor.ActorSystem
import javax.inject.Inject
import javax.inject.Named
import javax.inject.Provider
import javax.inject.Singleton
import akka.actor.ActorSystem
import akka.actor.typed.ActorRef
import akka.actor.typed.scaladsl.adapter._
import akka.actor.typed.scaladsl.Behaviors
import com.google.inject.name.Names
import com.google.inject.AbstractModule
import com.google.inject.TypeLiteral
Expand Down Expand Up @@ -122,7 +123,7 @@ object AkkaTypedDocSpec {
.toProvider(new Provider[ActorRef[HelloActor.SayHello]] {
@Inject var actorSystem: ActorSystem = _

def get() = actorSystem.spawn(new HelloActor, name)
def get() = actorSystem.spawn(Behaviors.setup(new HelloActor(_)), name)
})
.asEagerSingleton()
}
Expand All @@ -133,7 +134,7 @@ object AkkaTypedDocSpec {
@Inject var actorSystem: ActorSystem = _
@Inject var configuration: Configuration = _

def get() = actorSystem.spawn(new ConfiguredActor(configuration), name)
def get() = actorSystem.spawn(Behaviors.setup(new ConfiguredActor(_, configuration)), name)
})
.asEagerSingleton()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package scalaguide.akka.typed.fp
// #fp-configured-actor
import akka.actor.typed.ActorRef
import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.Behaviors
import com.google.inject.Provides
import play.api.Configuration
import play.api.libs.concurrent.ActorModule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ package scalaguide.akka.typed.fp
// #fp-hello-actor
import akka.actor.typed.ActorRef
import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.Behaviors

object HelloActor {
final case class SayHello(name: String, replyTo: ActorRef[String])
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,28 @@
package scalaguide.akka.typed.oo

// #oo-app-module
import akka.actor.ActorSystem
import akka.actor.typed.scaladsl.adapter._
import akka.actor.typed.scaladsl.Behaviors
import akka.actor.typed.ActorRef
import com.google.inject.AbstractModule
import com.google.inject.Provider
import com.google.inject.TypeLiteral
import javax.inject.Inject
import play.api.Configuration
import play.api.libs.concurrent.AkkaGuiceSupport

object AppModule extends AbstractModule with AkkaGuiceSupport {
override def configure() = {
bindTypedActor(classOf[HelloActor], "hello-actor")
bindTypedActor(classOf[ConfiguredActor], "configured-actor")
bindTypedActor(Behaviors.setup(context => new HelloActor(context)), "hello-actor")
bind(new TypeLiteral[ActorRef[ConfiguredActor.GetConfig]]() {})
.toProvider(new Provider[ActorRef[ConfiguredActor.GetConfig]] {
@Inject var actorSystem: ActorSystem = _
@Inject var configuration: Configuration = _

def get() = actorSystem.spawn(Behaviors.setup(context => new ConfiguredActor(context, configuration)), "configured-actor")
})
.asEagerSingleton()
}
}
// #oo-app-module
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,20 @@ package scalaguide.akka.typed.oo

// #oo-configured-actor
import akka.actor.typed.ActorRef
import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.AbstractBehavior
import akka.actor.typed.scaladsl.ActorContext
import javax.inject.Inject
import play.api.Configuration

object ConfiguredActor {
final case class GetConfig(replyTo: ActorRef[String])
}

final class ConfiguredActor @Inject()(configuration: Configuration)
extends AbstractBehavior[ConfiguredActor.GetConfig] {
final class ConfiguredActor(
context: ActorContext[ConfiguredActor.GetConfig],
configuration: Configuration,
) extends AbstractBehavior(context) {
import ConfiguredActor._
val config = configuration.get[String]("my.config")
def onMessage(msg: GetConfig) = {
Expand Down

0 comments on commit afb7fab

Please sign in to comment.