Do you think IIT Guwahati certified course can help you in your career?
No
Introduction
Akka is an open-source and free toolkit and runtime for designing highly concurrent, fault-tolerant, and distributed applications on the Java Virtual Machine. The Akka framework gives good abstraction for asynchronous, concurrent, and distributed programming, like Actors, Futures, and streams.
Akka contributes multiple programming models for concurrency, but it asserts actor-based concurrency. Language binding exists for both Scala and Java. Akka is written in the Scala language, and as of scala 2.10, the actors in the scala library are belittled in favor of Akka.
Integrating with Akka Typed
Akka 2.6 added the new typed Actor API(“Akka Typed”) as stable. Now, the typed API is the main API for Akka officially. In typed API, every actor must declare which message type it can handle, and the type system carries out that only messages of this type can be sent to the actor. As Play does not fully adopt Akka Typed, we already give some APIs to integrate it in Play apps.
Akka Actor Types styles
Akka’s Actor Typed API consists of two styles:
A functional programming style based on defining an actor's Behaviour s with values; and
An object-oriented style is based on defining an actor's Behaviour s with subclasses.
Below is the example of a simple actor that says “hello back”:
📘Scala FP
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],
)
def create(): Behavior[SayHello] = {
Behaviors.receiveMessage[SayHello] {
case SayHello(name, replyTo) =>
replyTo ! s"Hello, $name"
Behaviors.same
}
}
}
📘 Scala OO
import akka.actor.typed.ActorRef
import akka.actor.typed.Behavior
import akka.actor.typed.scaladsl.AbstractBehavior
import akka.actor.typed.scaladsl.ActorContext
import akka.actor.typed.scaladsl.Behaviors
object HelloActor {
final case class SayHello(
name: String,
replyTo: ActorRef[String],
)
def create(): Behavior[HelloActor.SayHello] = {
Behaviors.setup(context => new HelloActor(context))
}
}
final class HelloActor private (
context: ActorContext[HelloActor.SayHello],
) extends AbstractBehavior(context) {
import HelloActor._
def onMessage(msg: SayHello) = {
msg.replyTo ! s"Hello, ${msg.name}"
this
}
}
📘 Java FP
import akka.actor.typed.ActorRef;
import akka.actor.typed.Behavior;
import akka.actor.typed.javadsl.Behaviors;
public final class HelloActor {
public static final class SayHello {
public final String name;
public final ActorRef<String> replyTo;
public SayHello(String name, ActorRef<String> replyTo) {
this.name = name;
this.replyTo = replyTo;
}
}
public static Behavior<HelloActor.SayHello> create() {
return Behaviors.receiveMessage(
(SayHello message) -> {
message.replyTo.tell("Hello, " + message.name);
return Behaviors.same();
});
}
}
You can also try this code with Online Java Compiler
If our actor’s behavior has a variable state and is sometimes common in the object-oriented style, we need to ensure that we don’t share the same Behaviour instance for multiple Actorref s. Some general ways to avoid this problem are as follows:
📌 Consider a design without variable state
📌 Do not deluge the Behaviour instance by only exposing the Actorref instance, for example, by only binding the ActorRef
📌 If the objective is only to have a single instance of the actor, then make sure that both the Behaviour and ActorRef are singletons.
📌 Rather, there are meant to be multiple instances of the same actor, then make sure both ActorRef and Behaviour are named singletons in Guice by using @Named or .annotatedWith(Names.named(...)).
Compile-time dependency injection
Using compile time dependency injection for Akka Actor Typed needs creating the actor Behaviour value and using it to spawn the actor:
📘 Scala
import akka.actor.typed.scaladsl.adapter._
import play.api._
import play.api.routing.Router
final class AppComponents(context: ApplicationLoader.Context)
extends BuiltInComponentsFromContext(context)
with NoHttpFiltersComponents {
val router = Router.empty
val helloActor = {
actorSystem.spawn(HelloActor.create(), "hello-actor")
}
val configuredActor = {
val behavior = ConfiguredActor.create(configuration)
actorSystem.spawn(behavior, "configured-actor")
}
val main = new Main(helloActor, configuredActor)
}
📘 Java
import akka.actor.typed.ActorRef;
import akka.actor.typed.javadsl.Adapter;
import play.ApplicationLoader;
import play.BuiltInComponentsFromContext;
import play.mvc.EssentialFilter;
import play.routing.Router;
import java.util.Collections;
import java.util.List;
public final class AppComponents extends BuiltInComponentsFromContext {
public final ActorRef<HelloActor.SayHello> helloActor;
public final ActorRef<ConfiguredActor.GetConfig> configuredActor;
public final Main main;
public AppComponents(ApplicationLoader.Context context) {
super(context);
helloActor = Adapter.spawn(actorSystem(), HelloActor.create(), "hello-actor");
configuredActor =
Adapter.spawn(actorSystem(), ConfiguredActor.create(config()), "configured-actor");
main = new Main(helloActor, configuredActor);
}
@Override
public Router router() {
return Router.empty();
}
@Override
public List<EssentialFilter> httpFilters() {
return Collections.emptyList();
}
}
You can also try this code with Online Java Compiler
For runtime dependency injection, we need to use the “typed” method in AkkaGuiceSupport if we are using a functional programming style. For the object-oriented style, we must write a Provider for our ActorRef and bind it.
Following code shows injecting for a given component in your application :
📘Scala
import javax.inject.Inject
import javax.inject.Singleton
import akka.actor.typed.ActorRef
@Singleton final class Main @Inject() (
val helloActor: ActorRef[HelloActor.SayHello],
val configuredActor: ActorRef[ConfiguredActor.GetConfig],
)
📘Java
import akka.actor.typed.ActorRef;
import javax.inject.Inject;
import javax.inject.Singleton;
@Singleton
public final class Main {
public final ActorRef<HelloActor.SayHello> helloActor;
public final ActorRef<ConfiguredActor.GetConfig> configuredActor;
@Inject
public Main(
ActorRef<HelloActor.SayHello> helloActor,
ActorRef<ConfiguredActor.GetConfig> configuredActor) {
this.helloActor = helloActor;
this.configuredActor = configuredActor;
}
}
You can also try this code with Online Java Compiler
Play provides an incubating module for integration with Akka Cluster Sharding Typed, and to enable this module, we need to add the following dependencies to our build:
Usage
After properly including Cluster Sharding as a dependency, we can obtain an instance by using dependency injection. We have provided some helpers for both compile-time and runtime dependency injection. Here, notice that Play is on;y providing the DI mechanism.
The class instance that will be made available for injection is as follows:
Runtime dependency injection
Runtime dependency injection works as any other runtime DI module in Play, enabling that module automatically by adding the dependency, and an instance is available for injection.
Compile-time dependency injection
If we are using compile-time DI, we can get have access to the ClusterSharding by using the components as below :
📘Java
import play.Application;
import play.ApplicationLoader;
import play.BuiltInComponentsFromContext;
import play.controllers.AssetsComponents;
import play.routing.Router;
import play.cluster.sharding.typed.ClusterShardingComponents;
import play.filters.components.HttpFiltersComponents;
public class ComponentsWithClusterSharding extends BuiltInComponentsFromContext
implements ClusterShardingComponents, AssetsComponents, HttpFiltersComponents {
public ComponentsWithClusterSharding(ApplicationLoader.Context context) {
super(context);
}
@Override
public Router router() {
return Router.empty();
}
}
You can also try this code with Online Java Compiler
import play.api._
import play.api.ApplicationLoader.Context
import play.api.routing.Router
import play.api.cluster.sharding.typed.ClusterShardingComponents
class MyApplicationLoader extends ApplicationLoader {
def load(context: Context) = {
new ComponentsWithClusterSharding(context).application
}
}
class ComponentsWithClusterSharding(context: Context)
extends BuiltInComponentsFromContext(context)
with play.filters.HttpFiltersComponents
with ClusterShardingComponents {
lazy val router = Router.empty
}
Frequently Asked Questions
Describe the Akka cluster.
A fault-tolerant decentralized peer-to-peer Cluster Membership Service without a single point of failure or bottleneck is offered by Akka Cluster.
Why is the Akka framework used?
Akka framework helps to build software systems with high performance, and reliability, without sacrificing the developer’s productivity and joy.
What is a JVM application?
The JVM provides a portable execution environment for Java-based applications while managing system memory.
What are the actors in Akka?
Actors are objects that receive messages and respond to them by taking appropriate action.
Which statement terminates the JVM?
The JVM is shut down (by sending SIGTERM) Runtime. exit() or System. exit() is called by one of the threads.
Conclusion
In this article, we discussed Integrating with Akka Typed & cluster Sharding in detail. We started with introducing the Akka framework, and then we saw Integrating with Akka Typed with the help of both Java and Scala. We saw dependency injections and then cluster sharding for Akka Typed.