Akka eye for the Spring guy (or gal)

In this post, I will try to explain some of the Akka and Spray concepts in terms that would be familiar to Spring programmers. It will be a very brief explanation and I will make criminal simplifications. If you are seasoned Akka and Scala programmer, stop reading now; otherwise, dive in and see how Akka’s patterns map to the traditional request-response Spring code. We will build trivial application with RESTful API.

The Spring way

The crucial difference is structure of the application and its instantiation model. In contemporary Spring, we might use JavaConfig to describe the components and the dependencies between the components. We then let the Spring Framework instantiate the components and satisfy the dependencies. Typically, the components are singletons—the emergency handbrake of OOP… but we all know that. Let’s get back to the point of building application. In Spring, we’ll have:

public interface UserService {
  User get(Long id);

  List<User> findAll();

  void save(User user);
}

@Service
public class DefaultUserService implements UserService {
  
  public User get(Long id) {
  }

  List<User> findAll() {
  }

  public void save(User user) {
  }  

}

This represents the service tier–it contains the UserService component, which loads & saves the User entities to some underlying storage. Now, to provide a REST API around it, we need to write a controller:

@Controller("/users")
public class UserController {
  private final UserService userService;
  
  @Autowired
  public UserController(UserService userService) {
    this.userService = userService;
  }
  
  @RequestMapping(value = "/{id}", method = RequestMethod.GET)
  @ResponseBody
  public User view(Long id) {
    return this.userService.get(id);
  }

  @RequestMapping(value = "/", method = RequestMethod.GET)
  @ResponseBody
  public List<User> findAll() {
    return this.userService.findAll();
  }
 
  @RequestMapping(value = "/", method = RequestMethod.POST)
  @ResponseBody
  public User put(@Valid @RequestBody User user) {
    this.userService.save(user);
    return user;
  }
}

Booting Spring applications

That’s the Java code so far. However, this does not complete a Spring application. We need to give XML (or Java) configuration, and typically, we will turn this into a Java EE web application. We shall need two ApplicationContexts, one created by the ContextLoaderListener and one loaded by the DispatcherServlet. The ApplicationContext (the WebApplicationContext to be precise!) loaded by the DispatcherServlet sees every bean in the headless ApplicationContext loaded by the ContextLoaderListener.

To actually “boot” a Spring Web application, we prepare the WEB-INF/web.xml. Our favourite servlet container then reads this file and creates the components that ultimately prepare the two application contexts. The servlet container also directs incoming HTTP requests to our DispatcherServlet and the dispatcher servlet routes the requests though the innards of our application.

Akka & Spray

Let’s take a look at how we would structure the same application in Scala and Akka; using Spray to build the RESTful API tier. We are going to keep on separating the tiers as we did in Spring application, except now our UserService is going to be the UserActor and its interface is going to be the set of messages it handles and the set of replies it handles. So, turning the interface UserService to the messages, we arrive at:

case class GetUser(id: Long)
case class Save(user: User)
case class FindAll()

The UserActor will react to these messages by replying to the sender of the message with the appropriate response. This is the perfect opportunity to improve & refine the responses:

  • GetUser(id: Long) replies with Option[User]
  • Save(user: User) replies with User
  • FindAll() replies with List[User]

This allows us to complete the implementation of the actor:

class UserActor extends Actor {
  def receive = {
    case GetUser(id) =>
      // load the user, reply with None or Some(user)
      val user: Option[User] = ... 
      sender ! user
    case FindAll() =>
      // find all users
      val users: List[User] = ...
      sender ! users
    case Save(user) =>
      // persist the user
      sender ! user
  }
}

So, we have the middle tier of our application. The Spring interface’s methods map to the messages that the actors process; the parameters of the methods map to the values the messages carry; the return types map to the response types. Onwards to the controllers.

Just like the services, even the controllers are ultimately actors. These actors react to the incoming HTTP requests, perform whatever processing is required and then write to the response. Just like Spring’s controllers, Akka & Spray allows you to write the API tier without worrying about the underlying HTTP infrastructure. We construct Routes and then give these Routes to the Spray actors that handle the HTTP requests.

class UserService(implicit actorSystem: ActorSystem) 
  extends Directives 
  with LiftJsonSupport 
  with DefaultUnmarshallers 
  with DefaultMarshallers {

  // the name of the userActor (see trait Core)
  def userActor = actorSystem.actorFor("/user/user") 

  val route = 
    path("users") {
      get {
        path(LongNumber) { id =>
          completeWith( (userActor ? GetUser(id)).mapTo[Option[User]] )
        } ~
        path(Slash) {
          completeWith( (userActor ? FindAll()).mapTo[List[User]] )
        }
      } ~
      put {
        content(as[User]) { user =>
          completeWith( (userActor ? Save(user)).mapTo[User] ) 
        }
      }
    }

}

Notice the naming: we called this the UserService—by service here we mean functionality available to others. So, in Spray, the term service usually refers to the equivalent of Spring controllers. The controllers interpret the values of the HTTP requests, invoke the middle tier (our UserActor) and write to the responses.

Booting Akka & Spray applications

However, who or where creates these actors? In the Spring world, we’d sprinkle them with the @Component annotation and ask the Spring Framework to manage them for us. Akka does not have such annotation; moreover, the actors are not usually singletons! We need to create them ourselves. We shall define components that wrap our middle tier and our API tier.

trait Core {
  implicit def actorSystem: ActorSystem

  actorSystem.actorOf(Props[UserActor], "user")
}

This trait defines the actors that make up the core of our system—in this example, it is the single UserActor. This is therefore rough equivalent of Spring’s JavaConfiguration or, even more loosely, the XML configuration file.

Next, we create a component that wraps the APIs

trait API {
  this: Core =>

  val routes = new UserService().route :: Nil

  val svc: Route => ActorRef = 
    route => actorSystem.actorOf(Props(new HttpService(route)))

  val rootService = actorSystem.actorOf(
    props = Props(new RootService(
      svc(routes.head),
      routes.tail.map(svc):_*
    )),
    name = "root-service"
  )
}

The rough mapping to the Spring world is that the Core trait defines the headless ApplicationContext and that the API trait defines the WebApplicationContext. To put it yet another way, the components created in the Core trait are completely independent of any APIs; the components in the API trait depend on the components in the Core trait and provide the RESTful endpoints.

Finally, we can use Spray-can to boot the components and wrap them in real HTTP server:

trait Web {
  this: Api with Core =>

  val ioWorker = new IoWorker(actorSystem).start()

  val sprayCanServer = actorSystem.actorOf(
    Props(new HttpServer(ioWorker, MessageHandlerDispatch.SingletonHandler(
      actorSystem.actorOf(Props(new SprayCanRootService(rootService)))))),
    name = "http-server"
  )

  sprayCanServer ! HttpServer.Bind("localhost", 8080)

  actorSystem.registerOnTermination {
    ioWorker.stop()
  }

}

object Main extends App {
  implicit val system = ActorSystem("App")

  class Application(val actorSystem: ActorSystem) 
    extends Core with Api with Web
  
  new Application(system)

  sys.addShutdownHook {
    system.shutdown()
  }

}

Notice that our Akka/Spray application starts with equivalent of public static void main(String[] args)! There is no need for a servlet container of application server (but there is the option of having one, of course!).

The mapping

Spring Akka
Service interface & implementation Message case classes & actor that reacts to those messages
Controller Spray Route
Controller mappings HttpService & RootService
<mvc:annotation-driven />, various HttpMessageConverters Mixins of the UserService (particularly LiftJsonSupport, DefaultMarshallers and DefaultUnmarshallers)
XML / JavaConfiguration for the headless portion code in the Core trait
XML / JavaConfiguration for the web portion code in the API trait
Servlet container / App server Spray-can’s IoWorker/HttpServer

The crucial difference

I cannot go on any longer ignoring the elephant in the room!

So far, you might think that the only difference is in the naming and in the code we write to create the components. In Spring, we have the various ApplicationContexts with our components “living” in them; in Akka, we have to assemble the application ourselves. (But we can still use Spring, as I show here!). No, the crucial difference is that Akka applications are asynchronous by nature. Every operation is performed asynchronously, with the implied hope that by the time someone asks for the result, the underlying operation will have finished. This also explains the reason why Akka applications must run in Servlet 3.0 enabled container or in their own container, such as Spray-can.

So, Spring old dogs, jump in, write some Akka and Scala code and see how it compares with the tiers and components of your Spring applications.

This entry was posted in Jan's Blog and tagged , , . Bookmark the permalink.

12 Responses to Akka eye for the Spring guy (or gal)

  1. Steve says:

    Hi,

    Nice post! I think that Spray/Akka is a great combo.

    I thought that your readers might like to know the upcoming release of Spring (3.2) supports asynchronous processing as well.

    Cheers,
    -Steve

  2. Steve says:

    Sorry, messed up the url when posting. The details of Asynchornous processing in Spring 3.2 can be found here: http://goo.gl/iY9Ky

    Cheers,
    -Steve

  3. Jan Machacek says:

    Thanks for the comment–the Spring async support looks really cool.

  4. Eduardo says:

    Hi Jan,
    I am new to Akka/Spray (and have never used Spring) and this is a great introduction. Many thanks for the post!
    Would the code work with Akka 2.0 and Spray 1.0, or is it for the earlier version?

  5. Jan Machacek says:

    It’s Akka 2.0.1 and Spray 1.0-M2. The pattern would apply to previous versions of Akka and Spray.

  6. Pingback: This week in #Scala (22/06/2012) | Cake Solutions Team Blog

  7. Luyang Zhang says:

    Hello, I think there’s a typo at line 04 of trait API, should be new UserService().route, right? No route in UserActor. Btw, it’s really clear with layered traits setting up the whole system.

  8. Jan Machacek says:

    Aha! Thanks for spotting that; it should indeed be UserService.

    –J

  9. Thanks for the great post, it was very informative!

    There’s a minor typo in the last paragraph: “with the implied hope the by the time”

  10. Jan Machacek says:

    D’oh!

    Thanks for the comment and for spotting the typo.

    –J

  11. Pingback: Lift JSON & java.util.Set | Cake Solutions Team Blog

  12. Ramon Buckland says:

    Jan, Great post.
    Small typo:
    > case class Get(id: Long)
    should be
    > case class GetUser(id: Long)

Leave a Reply