Spring Integration

Spring Integration

Module stability: STABLE

Akkas integration with the Spring Framework supplies the Spring way of using the Typed Actor Java API and for CamelService configuration for Standalone Spring applications. It uses Spring’s custom namespaces to create Typed Actors, supervisor hierarchies and a CamelService in a Spring environment.

To use the custom name space tags for Akka you have to add the XML schema definition to your spring configuration. It is available at http://repo.akka.io/akka-1.3.1.xsd. The namespace for Akka is:

xmlns:akka="http://repo.akka.io/schema/akka"

Example header for Akka Spring configuration:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:akka="http://repo.akka.io/schema/akka"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
       http://repo.akka.io/schema/akka
       http://repo.akka.io/akka-1.3.1.xsd">

Actors

Actors in Java are created by extending the ‘UntypedActor’ class and implementing the ‘onReceive’ method.

Example how to create Actors with the Spring framework:

<akka:untyped-actor id="myActor"
                    implementation="com.biz.MyActor"
                    scope="singleton"
                    autostart="false"
                    depends-on="someBean"> <!-- or a comma-separated list of beans -->
        <property name="aProperty" value="somePropertyValue"/>
        <property name="aDependency" ref="someBeanOrActorDependency"/>
</akka:untyped-actor>

Supported scopes are singleton and prototype. Dependencies and properties are set with Springs <property/> element. A dependency can be either a <akka:untyped-actor/> or a regular <bean/>.

Get the Actor from the Spring context:

ApplicationContext context = new ClassPathXmlApplicationContext("akka-spring-config.xml");
ActorRef actorRef = (ActorRef) context.getBean("myActor");

Typed Actors

Here are some examples how to create Typed Actors with the Spring framework:

Creating a Typed Actor:

<beans>
  <akka:typed-actor id="myActor"
                    interface="com.biz.MyPOJO"
                    implementation="com.biz.MyPOJOImpl"
                    transactional="true"
                    timeout="1000"
                    scope="singleton"
                    depends-on="someBean"> <!-- or a comma-separated list of beans -->
       <property name="aProperty" value="somePropertyValue"/>
       <property name="aDependency" ref="someBeanOrActorDependency"/>
  </akka:typed-actor>
</beans>

Supported scopes are singleton and prototype. Dependencies and properties are set with Springs <property/> element. A dependency can be either a <akka:typed-actor/> or a regular <bean/>.

Get the Typed Actor from the Spring context:

ApplicationContext context = new ClassPathXmlApplicationContext("akka-spring-config.xml");
MyPojo myPojo = (MyPojo) context.getBean("myActor");

Remote Actors

For details on server managed and client managed remote actors see Remote Actor documentation.

Configuration for a client managed remote Actor

<akka:untyped-actor id="remote-untyped-actor"
                    implementation="com.biz.MyActor"
                    timeout="2000">
    <akka:remote host="localhost" port="9992" managed-by="client"/>
</akka:untyped-actor>

The default for ‘managed-by’ is “client”, so in the above example it could be left out.

Configuration for a server managed remote Actor

Server side

<akka:untyped-actor id="server-managed-remote-untyped-actor"
                    implementation="com.biz.MyActor">
    <akka:remote host="localhost" port="9990" managed-by="server"/>
</akka:untyped-actor>

<!-- register with custom service name -->
<akka:untyped-actor id="server-managed-remote-untyped-actor-custom-id"
                    implementation="com.biz.MyActor">
    <akka:remote host="localhost" port="9990" service-name="my-service"/>
</akka:untyped-actor>

If the server specified by ‘host’ and ‘port’ does not exist it will not be registered.

Client side

<!-- service-name could be custom name or class name -->
<akka:actor-for id="client-1" host="localhost" port="9990" service-name="my-service"/>

Configuration for a client managed remote Typed Actor

<akka:typed-actor id="remote-typed-actor"
                  interface="com.biz.MyPojo"
                  implementation="com.biz.MyPojoImpl"
                  timeout="2000">
    <akka:remote host="localhost" port="9999" />
</akka:typed-actor>

Configuration for a server managed remote Typed Actor

Sever side setup

<akka:typed-actor id="server-managed-remote-typed-actor-custom-id"
                  interface="com.biz.IMyPojo"
                  implementation="com.biz.MyPojo"
                  timeout="2000">
     <akka:remote host="localhost" port="9999" service-name="mypojo-service"/>
</akka:typed-actor>

Client side setup

<!-- always specify the interface for typed actor -->
<akka:actor-for id="typed-client"
                interface="com.biz.MyPojo"
                host="localhost"
                port="9999"
                service-name="mypojo-service"/>

Dispatchers

Configuration for a Typed Actor or Untyped Actor with a custom dispatcher

If you don’t want to use the default dispatcher you can define your own dispatcher in the spring configuration. For more information on dispatchers have a look at Dispatchers documentation.

<akka:typed-actor id="remote-typed-actor"
                  interface="com.biz.MyPOJO"
                  implementation="com.biz.MyPOJOImpl"
                  timeout="2000">
  <akka:dispatcher id="my-dispatcher" type="executor-based-event-driven" name="myDispatcher">
    <akka:thread-pool queue="unbounded-linked-blocking-queue" capacity="100" />
  </akka:dispatcher>
</akka:typed-actor>

<akka:untyped-actor id="untyped-actor-with-thread-based-dispatcher"
                    implementation="com.biz.MyActor">
      <akka:dispatcher type="thread-based" name="threadBasedDispatcher"/>
</akka:untyped-actor>

If you want to or have to share the dispatcher between Actors you can define a dispatcher and reference it from the Typed Actor configuration:

<akka:dispatcher id="dispatcher-1"
                 type="executor-based-event-driven"
                 name="myDispatcher">
  <akka:thread-pool queue="bounded-array-blocking-queue"
                    capacity="100"
                    fairness="true"
                    core-pool-size="1"
                    max-pool-size="20"
                    keep-alive="3000"
                    rejection-policy="caller-runs-policy"/>
</akka:dispatcher>

<akka:typed-actor id="typed-actor-with-dispatcher-ref"
                  interface="com.biz.MyPOJO"
                  implementation="com.biz.MyPOJOImpl"
                  timeout="1000">
    <akka:dispatcher ref="dispatcher-1"/>
</akka:typed-actor>

The following dispatcher types are available in spring configuration:

  • executor-based-event-driven
  • executor-based-event-driven-work-stealing
  • thread-based

The following queue types are configurable for dispatchers using thread pools:

  • bounded-linked-blocking-queue
  • unbounded-linked-blocking-queue
  • synchronous-queue
  • bounded-array-blocking-queue

If you have set up your IDE to be XSD-aware you can easily write your configuration through auto-completion.

Stopping Typed Actors and Untyped Actors

Actors with scope singleton are stopped when the application context is closed. Actors with scope prototype must be stopped by the application.

Supervisor Hierarchies

The supervisor configuration in Spring follows the declarative configuration for the Java API. Have a look at Akka’s approach to fault tolerance.

Example spring supervisor configuration

<beans>
  <akka:supervision id="my-supervisor">

    <akka:restart-strategy failover="AllForOne"
                           retries="3"
                           timerange="1000">
      <akka:trap-exits>
        <akka:trap-exit>java.io.IOException</akka:trap-exit>
      </akka:trap-exits>
    </akka:restart-strategy>

    <akka:typed-actors>
      <akka:typed-actor interface="com.biz.MyPOJO"
                        implementation="com.biz.MyPOJOImpl"
                        lifecycle="permanent"
                        timeout="1000"/>
      <akka:typed-actor interface="com.biz.AnotherPOJO"
                        implementation="com.biz.AnotherPOJOImpl"
                        lifecycle="temporary"
                        timeout="1000"/>
      <akka:typed-actor interface ="com.biz.FooBar"
                        implementation ="com.biz.FooBarImpl"
                        lifecycle="permanent"
                        transactional="true"
                        timeout="1000" />
    </akka:typed-actors>
  </akka:supervision>

  <akka:supervision id="supervision-untyped-actors">
    <akka:restart-strategy failover="AllForOne" retries="3" timerange="1000">
      <akka:trap-exits>
        <akka:trap-exit>java.io.IOException</akka:trap-exit>
        <akka:trap-exit>java.lang.NullPointerException</akka:trap-exit>
      </akka:trap-exits>
    </akka:restart-strategy>
    <akka:untyped-actors>
      <akka:untyped-actor implementation="com.biz.PingActor"
                        lifecycle="permanent"/>
      <akka:untyped-actor implementation="com.biz.PongActor"
                        lifecycle="permanent"/>
      </akka:untyped-actors>
  </akka:supervision>

</beans>

Get the TypedActorConfigurator from the Spring context

TypedActorConfigurator myConfigurator = (TypedActorConfigurator) context.getBean("my-supervisor");
MyPojo myPojo = (MyPOJO) myConfigurator.getInstance(MyPojo.class);

Property Placeholders

The Akka configuration can be made available as property placeholders by using a custom property placeholder configurer for Configgy:

<akka:property-placeholder location="akka.conf"/>

<akka:untyped-actor id="actor-1" implementation="com.biz.MyActor" timeout="${akka.actor.timeout}">
  <akka:remote host="${akka.remote.server.hostname}" port="${akka.remote.server.port}"/>
</akka:untyped-actor>

Camel configuration

For details refer to the Camel documentation:

Contents