AKKA 互相调用

SpringBoot 集成 AKKA 可以参考此文:SpringBoot 集成 AKKA

场景1:bossActor 收到信息,然后发给 worker1Actor 和 worker2Actor

controller 入口,初次调用 ActorRef.noSender()

@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();
    }
}

BossActor
接受 TestController 发送的信息,同时发送消息给 worker1Actor 和 worker2Actor

import akka.actor.ActorRef;
import akka.actor.Props;
import akka.actor.UntypedAbstractActor;

public class BossActor extends UntypedAbstractActor {

    private ActorRef worker1Actor;
    private ActorRef worker2Actor;

    public BossActor() {
        this.worker1Actor = this.context().actorOf(Props.create(Worker1Actor.class));
        this.worker2Actor = this.context().actorOf(Props.create(Worker2Actor.class));
    }

    @Override
    public void onReceive(Object message) {
        System.out.println("Boss 收到 master 的消息:" + message);
        worker1Actor.tell("I AM BOSS, TELLING WORKER1", self());
        worker2Actor.tell("I AM BOSS, TELLING WORKER2", self());
    }
}

Worker1Actor 和 Worker2Actor 获取 BossActor 的消息

import akka.actor.UntypedAbstractActor;

public class Worker1Actor extends UntypedAbstractActor {

    @Override
    public void onReceive(Object message) {
        System.out.println("worker1 收到 boss 消息:" + message);
    }
}
import akka.actor.UntypedAbstractActor;

public class Worker2Actor extends UntypedAbstractActor {

    @Override
    public void onReceive(Object message) {
        System.out.println("worker2 收到 boss 消息:" + message);
    }
}

打印输出
在这里插入图片描述
 
 
场景2:boss 发消息给 worker1,worker1 收到后发给 worker2,worker2 完成后返回 worker1,worker1再返回给 boss

分析难点:
1、由于 Actor 只能记住最后发消息给自己的人,所以 worker1 接到 worker2 消息后,getSender 只记住 worker2 ,找不到 boss 的地址
2、Actor 的 onReceive 方法接受的是消息,没有针对发送人,worker1 需要针对不同发送人 boss 和 worker2 做不同处理

针对问题2,我们可以设计一个实体 ReceiveDTO,里面包含 sender 发送人和 message 具体传参,所有消息严格实现这个类型

@Data
public class ReceiveDTO {
    String sender;
    Object message;
}

controller 入口,初次调用 ActorRef.noSender()

  @Resource
    private ActorSystem actorSystem;

    @PostMapping("/test")
    @Operation(summary = "test")
    public R search() {
        ActorRef pcm = actorSystem.actorOf(Props.create(BossActor.class));

        ReceiveDTO receiveDTO = new ReceiveDTO();
        receiveDTO.setSender("start");
        receiveDTO.setMessage("start");
        pcm.tell(receiveDTO, ActorRef.noSender());

        return R.ok();
    }

BossActor,根据 receiveDTO.getSender() 判断发送人是谁

import akka.actor.ActorRef;
import akka.actor.Props;
import akka.actor.UntypedAbstractActor;

public class BossActor extends UntypedAbstractActor {

    private ActorRef worker1Actor;

    public BossActor() {
        this.worker1Actor = this.context().actorOf(Props.create(Worker1Actor.class));
    }

    @Override
    public void onReceive(Object message) {
        ReceiveDTO receiveDTO = (ReceiveDTO) message;

        if (receiveDTO.getSender().equals("start")) {
            receiveDTO.setMessage("I AM BOSS, TELLING WORKER1");
            receiveDTO.setSender("boss");
            System.out.println("boss start");
            worker1Actor.tell(receiveDTO, self());
        }

        if (receiveDTO.getSender().equals("worker1")) {
            System.out.println("boss end 收到 worker1 消息: " + receiveDTO.getMessage());
        }
    }
}

Worker1Actor 接收 boss 信息时,同时把 boss 的 ActorRef 存到 bossActor,解决难题1

import akka.actor.ActorRef;
import akka.actor.Props;
import akka.actor.UntypedAbstractActor;

public class Worker1Actor extends UntypedAbstractActor {

    private ActorRef bossActor;
    private ActorRef worker2Actor;

    public Worker1Actor() {
        this.worker2Actor = this.context().actorOf(Props.create(Worker2Actor.class));
    }

    @Override
    public void onReceive(Object message) {

        ReceiveDTO receiveDTO = (ReceiveDTO) message;

        if (receiveDTO.getSender().equals("boss")) {
            System.out.println("worker1 收到 boss 消息: " + receiveDTO.getMessage());
            this.bossActor = getSender();
            ReceiveDTO receive1 = new ReceiveDTO();
            receive1.setMessage("I AM WORKER1, TELLING WORKER2");
            worker2Actor.tell(receive1, self());
        }

        if (receiveDTO.getSender().equals("worker2")) {
            System.out.println("worker1 收到 worker2 消息: " + receiveDTO.getMessage());
            ReceiveDTO receive1 = new ReceiveDTO();
            receive1.setMessage("I AM WORKER1, TELLING boss, job is over");
            receive1.setSender("worker1");
            bossActor.tell(receive1, self());
        }
    }
}

Worker2Actor

import akka.actor.UntypedAbstractActor;

public class Worker2Actor extends UntypedAbstractActor {

    @Override
    public void onReceive(Object message) {

        ReceiveDTO receiveDTO = (ReceiveDTO) message;
        System.out.println("worker2 收到 worker1 消息:" + receiveDTO.getMessage());

        ReceiveDTO receive1 = (ReceiveDTO) message;
        receive1.setSender("worker2");
        receive1.setMessage("I AM WORKER2, TELLING WORKER1");
        getSender().tell(receive1, self());
    }
}

打印输出

在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Akka 远程调用的实现基于 Akka Remoting 模块。以下是一个简单的示例: 首先,需要在项目中添加 Akka Remoting 依赖: ```xml <dependency> <groupId>com.typesafe.akka</groupId> <artifactId>akka-remote_2.11</artifactId> <version>2.5.9</version> </dependency> ``` 然后,定义一个远程 Actor,它可以通过网络接收和处理消息: ```java import akka.actor.AbstractActor; import akka.event.Logging; import akka.event.LoggingAdapter; public class RemoteActor extends AbstractActor { private LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this); @Override public Receive createReceive() { return receiveBuilder() .match(String.class, message -> { log.info("Received message: {}", message); getSender().tell("Hello from remote actor", getSelf()); }) .build(); } } ``` 接下来,在本地 Actor 中创建一个远程 Actor 的引用,并向其发送消息: ```java import akka.actor.ActorRef; import akka.actor.ActorSystem; import akka.actor.Props; import akka.pattern.Patterns; import scala.concurrent.Await; import scala.concurrent.duration.Duration; import java.util.concurrent.TimeUnit; public class LocalActor { public static void main(String[] args) throws Exception { ActorSystem system = ActorSystem.create("MySystem"); // 创建远程 Actor 的引用 ActorRef remoteActor = system.actorOf(Props.create(RemoteActor.class), "remoteActor"); // 向远程 Actor 发送消息,并等待其回复 String message = "Hello from local actor"; Object response = Patterns.ask(remoteActor, message, 5000).toCompletableFuture().get(5000, TimeUnit.MILLISECONDS); System.out.println("Received response: " + response); system.terminate(); } } ``` 在上面的代码中,我们使用 `Patterns.ask` 方法向远程 Actor 发送一条消息,并等待其回复。该方法返回一个 `Future` 对象,我们可以使用 `toCompletableFuture()` 方法将其转换为 Java 8 的 `CompletableFuture` 对象,从而方便地使用 `get` 方法等待结果。 以上就是一个简单的 Akka 远程调用的示例。在实际应用中,还需要配置 Akka Remoting 的一些参数,例如远程 Actor 的地址、端口等。具体配置方法可以参考 Akka 官方文档。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值