Akka and CDI: it runs in TomEE!


Akka is a very interesting solution for highly scalable systems but it misses some few things to be usable for big and enterprise applications. One of them is the IoC. For some more advanced applications it can be transactions…

We sometimes see some spring integration but now that JavaEE proposes a real IoC container it worth looking at how it can work.

Technical idea

First you need to note akka classes are not (or not often at least) proxiable. It doesn’t sound an issue but it means you’ll not be able to use CDI scope with them (even with CDI producer methods).

Then it is pretty easy to add ActorRef in CDI context: create it manually from your ActorSystem then set it to a static field still not hitten and annotated @Produces. The drawback is you need to do it for all ActorRef you need to add in CDI context. The other thing to take care is to use a qualifier because the type you’ll use will be ActorRef (for untyped actors). Finally the last thing to take care is you’ll get @Dependent beans where you can want @ApplicationScoped beans.

The opposite is not more complicated since you need to write a custom ActorFactory (UntypedActorFactory probably) to instantiate you actor (and potientially inject anything you can want inside).

PoC

I did some tests in TomEE (snapshot, not sure it is important or not) and wrote a CDI extension about it : more info on CDI-Akka

It basically allows you to get ActorRef injections using:

@Inject
@Akka(classOf[PingActor])
private var ping: ActorRef = null

You can inject the same way the ActorSystem:

@Inject
@Akka(classOf[ActorSystem])
private var system: ActorSystem = null

The “global” usage of @Akka even for the system is simply to avoid conflicts.

The injected instance are @ApplicationScoped (functionally, not in CDI) which means that two injections will be the same instance.

The extension basically find all Actor classes managed by CDI like the following one:

class PongActor extends Actor {
  def receive = {
    case Pong =>
      sender ! Ping
  }
}

then get an ActorSystem (it creates “AkkaCdi” ones if noone was in the CDI context). To register a custom one simply use:

@Produces def system() = ActorSystem("PingPongTomEE")

and finally add all found actors getting their instances from CDI…it means your actors can look like:

class PingActor extends Actor {
  @Inject
  private var business: SomeBusiness = _

  def receive = {
    case Ping =>
      business.sendPong()
  }
}

Finally you simply have to write your actors, be sure they can be CDI managed beans, create a custom ActorSystem if you need it and your system should be up and CDI compliant.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s