Akka经典Actor向Typed Actor使用Patterns.ask()可行吗?求Java示例
经典Actor调用Typed Actor的Ask模式实现
这种跨经典与Typed Actor的Ask调用是完全可行的,你遇到超时的核心原因是回复目标错误:Patterns.ask会生成一个临时Actor来等待响应,你需要让Typed Actor回复给这个临时Actor,而非原经典Actor的self()。
1. 定义跨Actor的消息协议
import akka.actor.typed.ActorRef; // 统一的消息协议,包含请求和响应 public interface CrossActorProtocol { // 给Typed Actor的请求消息,携带回复目标 record AskRequest(String content, ActorRef<AskResponse> replyTo) implements CrossActorProtocol {} // 响应消息 record AskResponse(String result) implements CrossActorProtocol {} }
2. 实现Typed Actor
Typed Actor接收请求后,直接回复给消息中指定的replyTo:
import akka.actor.typed.Behavior; import akka.actor.typed.javadsl.AbstractBehavior; import akka.actor.typed.javadsl.Behaviors; import akka.actor.typed.javadsl.Receive; public class MyTypedActor extends AbstractBehavior<CrossActorProtocol> { public static Behavior<CrossActorProtocol> create() { return Behaviors.setup(MyTypedActor::new); } private MyTypedActor(ActorContext<CrossActorProtocol> context) { super(context); } @Override public Receive<CrossActorProtocol> createReceive() { return newReceiveBuilder() .onMessage(CrossActorProtocol.AskRequest.class, this::handleAskRequest) .build(); } private Behavior<CrossActorProtocol> handleAskRequest(CrossActorProtocol.AskRequest request) { // 处理请求逻辑 String processedResult = "Typed Actor processed: " + request.content(); // 回复给指定的replyTo(即Patterns.ask生成的临时Actor) request.replyTo().tell(new CrossActorProtocol.AskResponse(processedResult)); return this; } }
3. 实现经典Actor并调用Ask
经典Actor通过Adapter.toClassic()将Typed Actor转为经典ActorRef,使用Patterns.ask时,将临时回复目标(由ask传入)转成Typed ActorRef并放入请求消息:
import akka.actor.AbstractActor; import akka.actor.ActorRef; import akka.actor.Props; import akka.pattern.Patterns; import akka.util.Timeout; import java.util.concurrent.CompletionStage; import java.util.concurrent.TimeUnit; public class MyClassicActor extends AbstractActor { private final ActorRef<CrossActorProtocol> typedActor; private final Timeout askTimeout = Timeout.create(5, TimeUnit.SECONDS); // 构造函数注入Typed Actor引用 public MyClassicActor(ActorRef<CrossActorProtocol> typedActor) { this.typedActor = typedActor; } public static Props props(ActorRef<CrossActorProtocol> typedActor) { return Props.create(MyClassicActor.class, () -> new MyClassicActor(typedActor)); } @Override public Receive createReceive() { return receiveBuilder() .onMessage(String.class, this::handleAskTrigger) .build(); } private void handleAskTrigger(String requestContent) { // 将Typed Actor转为经典ActorRef,用于Patterns.ask调用 ActorRef classicTypedActor = akka.actor.typed.javadsl.Adapter.toClassic(typedActor); // 调用Patterns.ask:第二个参数是函数,接收临时回复目标(经典ActorRef),构造请求消息 CompletionStage<Object> askFuture = Patterns.ask( classicTypedActor, // 将临时经典ActorRef转为Typed ActorRef,作为回复目标传入请求 replyToClassic -> new CrossActorProtocol.AskRequest(requestContent, akka.actor.typed.javadsl.Adapter.toTyped(replyToClassic)), askTimeout ); // 处理Ask的结果 askFuture.whenComplete((response, error) -> { if (error != null) { // 处理错误,回复给触发当前操作的发送者 getSender().tell(new akka.actor.Status.Failure(error), getSelf()); } else { // 回复成功结果 getSender().tell(response, getSelf()); } }); } }
4. 启动Actor系统并测试
import akka.actor.ActorSystem; import akka.actor.typed.javadsl.Adapter; public class CrossActorTest { public static void main(String[] args) { // 启动经典Actor系统 ActorSystem classicSystem = ActorSystem.create("CrossActorSystem"); // 创建Typed Actor(通过Adapter嵌入经典系统) ActorRef<CrossActorProtocol> typedActor = Adapter.spawn(classicSystem, MyTypedActor.create(), "MyTypedActor"); // 创建经典Actor ActorRef classicActor = classicSystem.actorOf(MyClassicActor.props(typedActor), "MyClassicActor"); // 发送消息触发Ask调用 classicActor.tell("Hello from Classic Actor!", ActorRef.noSender()); } }
关键注意点
- 必须将Patterns.ask生成的临时回复目标(而非经典Actor自身的self())传递给Typed Actor,作为回复的目标
- 使用
akka.actor.typed.javadsl.Adapter工具类完成经典与Typed ActorRef之间的双向转换 - 确保超时时间设置合理,覆盖Typed Actor的处理耗时
内容的提问来源于stack exchange,提问作者Chad Showalter
相关产品推荐
相关产品推荐

