Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you write an Akka Typed Extension for Spring for constructor dependency injection?

Before Akka 2.6, or with classic Actors, one can write an Akka Extension to have access to Spring's @Inject annotation in Akka untyped actors.

One example of this is: https://github.com/typesafehub/activator-akka-java-spring/blob/master/src/main/java/sample/SpringExtension.java

However, this does not work for the new Akka Typed actors.

Akka's documentation does not show how to make such an extension (but it does show how to make simple extensions: https://doc.akka.io/docs/akka/current/typed/extending.html#building-an-extension).

So far, I wrote this beginning of extension, but I don't know how to link Spring's ApplicationContext with the actor system:

import org.springframework.context.ApplicationContext;

import akka.actor.typed.ActorSystem;
import akka.actor.typed.Extension;
import akka.actor.typed.ExtensionId;

public class SpringExtension implements Extension {

  private volatile ApplicationContext applicationContext;

  private SpringExtension(final ActorSystem<?> system) {
    // TODO: What do you put here?
  }

  void initialize(final ApplicationContext applicationContext) {
    this.applicationContext = applicationContext;
  }

  public static class Id extends ExtensionId<SpringExtension> {

    private static final Id instance = new Id();

    private Id() {}

    // called once per ActorSystem
    @Override
    public SpringExtension createExtension(final ActorSystem<?> system) {
      return new SpringExtension(system);
    }

    public static SpringExtension get(final ActorSystem<?> system) {
      return instance.apply(system);
    }
  }
}

How do you write an Akka Extension for Typed Actors allowing to use Spring DI in typed actors?

like image 586
Jiehong Avatar asked Jan 30 '20 16:01

Jiehong


People also ask

What is Akka typed?

Akka “Typed Actors”, now replaced by Akka Typed, were an implementation of the Active Objects pattern. Essentially turning method invocations into asynchronous dispatch instead of synchronous that has been the default way since Smalltalk came out.

Does spring use Akka?

Adding Spring Support via Akka Extension. The easiest way to integrate Spring with Akka is through an Akka extension. An extension is a singleton instance created per actor system.

What is actor model in Akka?

Akka Actors The Actor Model provides a higher level of abstraction for writing concurrent and distributed systems. It alleviates the developer from having to deal with explicit locking and thread management, making it easier to write correct concurrent and parallel systems.


1 Answers

May be this is not exactly what you need, but I think found a way how to inject typed actors without using an extension.

We can create Behavior as a bean, inject all needed dependencies and pass it to another actor, where spawn the actor based on defined Behavior.

Let's assume we have PrintActor that can print messages using PrintService, and GreetActor that uses GreetService and spawns PrintActor. We can define beans like this:

@Bean
public Behavior<String> printActorBehavior(PrintService printService) {
    return Behaviors.setup(ctx -> new PrintActor(ctx, printService));
}

@Bean
public Behavior<GreetActor.Greet> greetActorBehavior(GreetService greetService, 
                                                     Behavior<String> printerActorBehavior) {
    return Behaviors.setup(ctx -> new GreetActor(ctx, greetService, printerActorBehavior));
}

And then, in GreetActor we just create actor from injected Behavior by calling getContext().spawn(printerActorBehavior, "printer");

public class GreetActor extends AbstractBehavior<GreetActor.Greet> {
    private GreetService greetService;
    private Behavior<String> printerActorBehavior;

    public GreetActor(ActorContext<Greet> context, 
                      GreetService greetService,
                      Behavior<String> printerActorBehavior) {
        super(context);
        this.greetService = greetService;
        this.printerActorBehavior = printerActorBehavior;
    }

    @Override
    public Receive<Greet> createReceive() {
        return newReceiveBuilder()
                .onMessage(Greet.class, this::onGreet)
                .build();
    }

    private Behavior<Greet> onGreet(Greet msg) {
        ActorRef<String> printer = getContext().spawn(printerActorBehavior, "printer");
        printer.tell(greetService.greet(msg.name));
        return this;
    }

    @Value
    static class Greet {
        String name;
    }
}

Since we can not create actors from outside of actor system in Akka Typed, I think there is no proper way to inject ActorRef with Spring.

We can try to inject Spring context into actor, spawn some actors and put them into Spring context, but I think this is not a good way to work with both frameworks.

like image 153
Shide93 Avatar answered Sep 22 '22 02:09

Shide93