SpringBoot integration AKKA

Article directory

  • Application scenarios
  • Integrate with SpringBoot
  • Example

Application scenarios

AKKA is an open source framework for building highly concurrent, distributed and fault-tolerant applications. It is based on the Actor model and provides powerful concurrency abstractions and tools suitable for various business scenarios. Here are some examples of common business scenarios using the AKKA framework:

  1. Real-time data processing: AKKA provides a lightweight Actor model that can be used to process real-time data streams. You can create multiple Actors to handle different parts of the data and use messaging mechanisms to communicate and coordinate. This is very useful in scenarios such as real-time monitoring, real-time analysis and real-time push.

  2. Concurrent task execution: AKKA’s Actor model makes the execution of concurrent tasks simple. You can break the task into multiple independent Actors and have them execute in parallel. Each Actor can be responsible for processing a part of the task, and coordinate and summarize the results through message passing. This is very useful in scenarios such as batch processing, parallel computing and task scheduling.

  3. Distributed system: AKKA provides a distributed Actor model that can distribute Actor instances on multiple nodes. This makes building distributed systems much easier. You can use AKKA’s remote Actor and cluster functions to implement distributed task distribution, data sharing and fault tolerance mechanisms.

  4. Microservice architecture: AKKA can be used as the basis for building a microservice architecture. Each microservice can be composed of one or more Actors and communicate using messaging. AKKA’s fault tolerance mechanism and supervision strategy can help achieve high availability and fault tolerance of microservices.

  5. Real-time communication and chat applications: AKKA provides an efficient messaging mechanism suitable for real-time communication and chat applications. Each user can be represented by an Actor, and messages can be delivered through mailboxes between Actors. This makes it easier to implement real-time chat, notifications, and collaboration features.

Integrated with SpringBoot

Add dependencies

<dependency>
    <groupId>com.typesafe.akka</groupId>
    <artifactId>akka-slf4j_2.12</artifactId>
    <version>2.5.22</version>
</dependency>

Integration Essentials

Since the creation of ActorSystem does not rely on the new method, but through the create method, we need to write a Bean to produce ActorSystem. In addition, Actor is also created through the actorOf() method, so we also need to write a method to produce Actor references. Akka provides the IndirectActorProducer interface. By implementing this interface, we can implement DI (dependency injection). After integrating SpringBoot, dependencies within the scope of ActorSystem will be managed by SpringBoot, and each ActorSystem will hold an ApplicationContext.

Actor Producer

Implement IndirectActorProducer, which is used to produce Actors. Since it is managed by Spring, the ApplicationContext object and bean name must be

import akka.actor.Actor;
import akka.actor.IndirectActorProducer;
import org.springframework.context.ApplicationContext;

public class ActorProducer implements IndirectActorProducer {<!-- -->
    private ApplicationContext context;
    private String beanName;

    public ActorProducer(ApplicationContext context,String beanName){<!-- -->
        this.context=context;
        this.beanName=beanName;
    }

    @Override
    public Actor produce() {<!-- -->
        return (Actor) context.getBean(beanName);
    }

    @Override
    public Class<? extends Actor> actorClass() {<!-- -->
        return (Class<? extends Actor>) context.getType(beanName);
    }
}

Extensions

Constructs Props, which can be used to create ActorRef objects

import akka.actor.Extension;
import akka.actor.Props;
import org.springframework.context.ApplicationContext;

public class SpringExt implements Extension {<!-- -->
    private ApplicationContext context;

    public void init(ApplicationContext context) {<!-- -->
        System.out.println("applicationContext initialization...");
        this.context = context;
    }

    public Props create(String beanName) {<!-- -->
        return Props.create(ActorProducer.class, this.context, beanName);
    }
}

Provider of extensions

Through SpringExtProvider we can get SpringExt, through SpringExt we can use Props to create ActorRef objects

import akka.actor.AbstractExtensionId;
import akka.actor.ExtendedActorSystem;

public class SpringExtProvider extends AbstractExtensionId<SpringExt> {<!-- -->
    private static SpringExtProvider provider = new SpringExtProvider();

    public static SpringExtProvider getInstance() {<!-- -->
        return provider;
    }

    @Override
    public SpringExt createExtension(ExtendedActorSystem extendedActorSystem) {<!-- -->
        return new SpringExt();
    }
}

Configuration class
Used to initialize the ActorSystem and scan the Actors included in the container

import akka.actor.ActorSystem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ScanConfig {<!-- -->
    private final ApplicationContext context;

    @Autowired
    public ScanConfig(ApplicationContext context) {<!-- -->
        this.context = context;
    }

    @Bean
    public ActorSystem createSystem() {<!-- -->
        ActorSystem system = ActorSystem.create("system");
        SpringExtProvider.getInstance().get(system).init(context);
        return system;
    }
}

Example

Create a Controller

import akka.actor.ActorRef;
import akka.actor.ActorSystem;
import akka.actor.Props;
import com.sie.mbm.mom.common.core.util.R;
import com.sie.mbm.mom.framework.security.annotation.Inner;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;

@Tag(name = "test")
@RestController
@RequestMapping("/test")
@Validated
@Inner(value = false)
public class TestController {<!-- -->

    @Resource
    private ActorSystem actorSystem;

    @PostMapping("/test")
    @Operation(summary = "test")
    public R search( ) {<!-- -->
        ActorRef pcm = actorSystem.actorOf(Props.create(BossActor.class));
        pcm.tell("I AM MASTER.TELLING BOSS", ActorRef.noSender());
        return R.ok();
    }
}

Create an Actor to receive messages

import akka.actor.UntypedAbstractActor;

public class BossActor extends UntypedAbstractActor {<!-- -->

    @Override
    public void onReceive(Object message) {<!-- -->

        System.out.println(message);

    }
}

successful output