{"id":21673632,"url":"https://github.com/aliakh/demo-akka-spring","last_synced_at":"2025-06-21T03:40:19.413Z","repository":{"id":133290356,"uuid":"57031572","full_name":"aliakh/demo-akka-spring","owner":"aliakh","description":"'Using Akka with Spring' article and source code.","archived":false,"fork":false,"pushed_at":"2020-07-11T12:54:46.000Z","size":63,"stargazers_count":80,"open_issues_count":0,"forks_count":54,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-03-25T23:41:48.099Z","etag":null,"topics":["akka-actors","java","spring","springboot"],"latest_commit_sha":null,"homepage":"","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/aliakh.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-04-25T10:03:05.000Z","updated_at":"2024-12-11T11:23:32.000Z","dependencies_parsed_at":null,"dependency_job_id":"cb1d22d6-fcda-4a89-bb11-deb9542b098d","html_url":"https://github.com/aliakh/demo-akka-spring","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aliakh%2Fdemo-akka-spring","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aliakh%2Fdemo-akka-spring/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aliakh%2Fdemo-akka-spring/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/aliakh%2Fdemo-akka-spring/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/aliakh","download_url":"https://codeload.github.com/aliakh/demo-akka-spring/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248514207,"owners_count":21116903,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["akka-actors","java","spring","springboot"],"created_at":"2024-11-25T13:40:12.941Z","updated_at":"2025-04-12T04:11:37.687Z","avatar_url":"https://github.com/aliakh.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Using Akka with Spring\n\n## Introduction\n\nIn this article is explained how to integrate Akka actors into Spring _console_ and _web_ applications.\n\n## Spring console application with Akka\n\nAkka _ActorSystem_ can be integrated with Spring _ApplicationContext_ in three steps.\n\nFirstly, the _SpringActorProducer_ is used to create actors by getting them as Spring beans from the _ApplicationContext_ by name (instead of creating actors from their classes by Java reflection).\n\n```\npublic class SpringActorProducer implements IndirectActorProducer {\n\n   private final ApplicationContext applicationContext;\n   private final String actorBeanName;\n\n   public SpringActorProducer(ApplicationContext applicationContext, String actorBeanName) {\n       this.applicationContext = applicationContext;\n       this.actorBeanName = actorBeanName;\n   }\n\n   @Override\n   public Actor produce() {\n       return (Actor) applicationContext.getBean(actorBeanName);\n   }\n\n   @Override\n   public Class\u003c? extends Actor\u003e actorClass() {\n       return (Class\u003c? extends Actor\u003e) applicationContext.getType(actorBeanName);\n   }\n}\n```\n\nSecondly, an Akka _Extension_ is used to add additional functionality to the _ActorSystem_. The _SpringExtension_ uses Akka _Props_ to create actors with the _SpringActorProducer_.\n\n```\n@Component\npublic class SpringExtension implements Extension {\n\n   private ApplicationContext applicationContext;\n\n   public void initialize(ApplicationContext applicationContext) {\n       this.applicationContext = applicationContext;\n   }\n\n   public Props props(String actorBeanName) {\n       return Props.create(SpringActorProducer.class, applicationContext, actorBeanName);\n   }\n}\n```\n\nThirdly, a Spring _@Configuration_ is used to provide the _ActorSystem_ as a Spring bean. The _ApplicaionConfiguration_ creates the _ActorSystem_ from the Akka configuration, overriding the _application.conf_ file, and registers the _SpringExtension_ in it.\n\n```\n@Configuration\nclass ApplicationConfiguration {\n\n   @Autowired\n   private ApplicationContext applicationContext;\n\n   @Autowired\n   private SpringExtension springExtension;\n\n   @Bean\n   public ActorSystem actorSystem() {\n       ActorSystem actorSystem = ActorSystem.create(\"demo-actor-system\", akkaConfiguration());\n       springExtension.initialize(applicationContext);\n       return actorSystem;\n   }\n\n   @Bean\n   public Config akkaConfiguration() {\n       return ConfigFactory.load();\n   }\n}\n```\n\nThe _WorkerActor_ is a stateful actor that receives and sends messages (they have to be immutable) with other actors inside the _onReceive_ method. Don't forget to use the _unhandled_ method if the received message doesn't match. Notice that actors have to be defined in the Spring _prototype_ scope.\n\n```\n@Component(\"workerActor\")\n@Scope(\"prototype\")\npublic class WorkerActor extends UntypedActor {\n\n   @Autowired\n   private BusinessService businessService;\n\n   private final CompletableFuture\u003cMessage\u003e completableFuture;\n\n   public WorkerActor(CompletableFuture\u003cMessage\u003e completableFuture) {\n       this.completableFuture = completableFuture;\n   }\n\n   @Override\n   public void onReceive(Object message) throws Exception {\n       businessService.perform(this + \" \" + message);\n\n       if (message instanceof Message) {\n           completableFuture.complete((Message) message);\n       } else {\n           unhandled(message);\n       }\n\n       getContext().stop(self());\n   }\n}\n```\n\nThe _BusinessService_ is a simple service that is injected in the _WorkerActor_ by Spring.\n\n```\n@Service\npublic class BusinessService {\n\n   private final Logger logger = LoggerFactory.getLogger(this.getClass());\n\n   public void perform(Object o) {\n       logger.info(\"Perform: {}\", o);\n   }\n}\n```\n\nThe example application is a console Spring Boot application. A Spring Boot _CommandLineRunner_ is used to get a _WorkerActor_ from the _ActorSystem_ inside the _ApplicationContext_, to send a sequence of requests and receive a response, and finally to terminate the _ActorSystem_. Notice that the _Await.result_ method is blocking, so it should be used in very limited cases (e.g. in integration the actor-based part with the rest of the application or in the unit tests).\n\n```\n@Component\nclass Runner implements CommandLineRunner {\n\n   private final Logger logger = LoggerFactory.getLogger(this.getClass());\n\n   @Autowired\n   private ActorSystem actorSystem;\n\n   @Autowired\n   private SpringExtension springExtension;\n\n   @Override\n   public void run(String[] args) throws Exception {\n       try {\n           ActorRef workerActor = actorSystem.actorOf(springExtension.props(\"workerActor\"), \"worker-actor\");\n\n           workerActor.tell(new WorkerActor.Request(), null);\n           workerActor.tell(new WorkerActor.Request(), null);\n           workerActor.tell(new WorkerActor.Request(), null);\n\n           FiniteDuration duration = FiniteDuration.create(1, TimeUnit.SECONDS);\n           Future\u003cObject\u003e awaitable = Patterns.ask(workerActor, new WorkerActor.Response(), Timeout.durationToTimeout(duration));\n\n           logger.info(\"Response: \" + Await.result(awaitable, duration));\n       } finally {\n           actorSystem.terminate();\n           Await.result(actorSystem.whenTerminated(), Duration.Inf());\n       }\n   }\n}\n```\n\n## Spring Web application with Akka\n\nIn the previous section was explained how to use Akka in a Spring _console_ application. The main purpose of that example was to illustrate how to get actors from Spring _ApplicationContext_. But the drawback of this example was a blocking call between the actor-based part and the rest of the application. Such usage can cease all Akka advantages in production applications. So in this section is explained how to use Akka in an asynchronous and non-blocking Spring _web_ application.\n\nFor this can be used asynchronous request processing in Spring MVC that is based on Servlet 3.0/3.1 specification. Instead of returning a value, a _@Controller_ method should return a _DeferredResult_ or a _Callable_ of the value. In multi-tier applications, a _@Service_ method should return a _future_ (also known as _promise_, _delay_, or _deferred)_ - a proxy to a value that isn’t completed yet. There are some interfaces that have support for _future_ processing in their frameworks:\n\n*   _java.util.concurrent.CompletableFuture_ (Java 8)\n*   _rx.Observable_ (RxJava)\n*   _org.springframework.util.concurrent.ListenableFuture_ (Spring Core)\n*   _com.google.common.util.concurrent.ListenableFuture_ (Google Guava)\n\nThe main difference with the previous example application is that the _WorkerActor_ has a non-default constructor. That required refactoring of _SpringActorProducer_ and _SpringExtension_ to have the ability to pass the constructor arguments.\n\n```\npublic class SpringActorProducer implements IndirectActorProducer {\n\n   private final ApplicationContext applicationContext;\n   private final String actorBeanName;\n   private final Object[] args;\n\n   public SpringActorProducer(ApplicationContext applicationContext, String actorBeanName, Object... args) {\n       this.applicationContext = applicationContext;\n       this.actorBeanName = actorBeanName;\n       this.args = args;\n   }\n\n   @Override\n   public Actor produce() {\n       if (args == null) {\n           return (Actor) applicationContext.getBean(actorBeanName);\n       } else {\n           return (Actor) applicationContext.getBean(actorBeanName, args);\n       }\n   }\n\n   @Override\n   public Class\u003c? extends Actor\u003e actorClass() {\n       return (Class\u003c? extends Actor\u003e) applicationContext.getType(actorBeanName);\n   }\n}\n\n@Component\npublic class SpringExtension implements Extension {\n\n   private ApplicationContext applicationContext;\n\n   public void initialize(ApplicationContext applicationContext) {\n       this.applicationContext = applicationContext;\n   }\n\n   public Props props(String actorBeanName) {\n       return Props.create(SpringActorProducer.class, applicationContext, actorBeanName);\n   }\n\n   public Props props(String actorBeanName, Object... args) {\n       return Props.create(SpringActorProducer.class, applicationContext, actorBeanName, args);\n   }\n}\n```\n\nThe example application is a web application that is based on Spring Boot. In the _CompletableFutureService.get_ method, a _WorkerActor_ is created with an incomplete _CompletableFuture_ as a constructor parameter. Notice how the Spring _prototype_-scope actor is injected into the _singleton_-scope _CompletableFutureService_. Then a _Message_ is sent to the _WorkerActor_ with the _tell_ method.\n\n```\n@Service\npublic class CompletableFutureService {\n\n   @Autowired\n   private ActorSystem actorSystem;\n\n   @Autowired\n   private SpringExtension springExtension;\n\n   public CompletableFuture\u003cMessage\u003e get(String payload, Long id) {\n       CompletableFuture\u003cMessage\u003e completableFuture = new CompletableFuture\u003c\u003e();\n       ActorRef workerActor = actorSystem.actorOf(springExtension.props(\"workerActor\", completableFuture), \"worker-actor\");\n       workerActor.tell(new Message(payload, id), null);\n       return completableFuture;\n   }\n}\n```\n\nThe _WorkerActor_ immediately completes the _CompletableFuture_, but in real applications, there can be more complicated interaction between actors. Notice that at the end of the _onReceive_ method the _WorkerActor_ is destroyed. It’s not an issue because creating and destroying actors is a cheap operation (should the actor be saved or destroyed and recreated again depends on the actors’ supervision strategy in the application).\n\n```\n@Component(\"workerActor\")\n@Scope(\"prototype\")\npublic class WorkerActor extends UntypedActor {\n\n   @Autowired\n   private BusinessService businessService;\n\n   private final CompletableFuture\u003cMessage\u003e completableFuture;\n\n   public WorkerActor(CompletableFuture\u003cMessage\u003e completableFuture) {\n       this.completableFuture = completableFuture;\n   }\n\n   @Override\n   public void onReceive(Object message) throws Exception {\n       businessService.perform(this + \" \" + message);\n\n       if (message instanceof Message) {\n           completableFuture.complete((Message) message);\n       } else {\n           unhandled(message);\n       }\n\n       getContext().stop(self());\n   }\n}\n```\n\nFinally, in the _DeferredResultController.getAsyncNonBlocking_ method, the _CompletableFuture_ is converted to a _DeferredResult_.\n\n```\n@RestController\npublic class DeferredResultController {\n\n   private static final Long DEFERRED_RESULT_TIMEOUT = 1000L;\n\n   private final AtomicLong id = new AtomicLong(0);\n\n   @Autowired\n   private CompletableFutureService completableFutureService;\n\n   @RequestMapping(\"/async-non-blocking\")\n   public DeferredResult\u003cMessage\u003e getAsyncNonBlocking() {\n       DeferredResult\u003cMessage\u003e deferredResult = new DeferredResult\u003c\u003e(DEFERRED_RESULT_TIMEOUT);\n       CompletableFuture\u003cMessage\u003e completableFuture = completableFutureService.get(\"async-non-blocking\", id.getAndIncrement());\n       completableFuture.whenComplete((result, error) -\u003e {\n           if (error != null) {\n               deferredResult.setErrorResult(error);\n           } else {\n               deferredResult.setResult(result);\n           }\n       });\n       return deferredResult;\n   }\n}\n```\n\n## Conclusion\n\nCode examples are available in the [GitHub repository](https://github.com/aliakh/demo-akka-spring).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faliakh%2Fdemo-akka-spring","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Faliakh%2Fdemo-akka-spring","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Faliakh%2Fdemo-akka-spring/lists"}