Akka and Spring integration



我正在尝试让 akka 使用弹簧应用程序。 这是一款非常适合 akka 模型的搜索应用程序。关于此集成的大多数在线和typesafe示例都谈到了使用akka扩展来注入spring应用程序上下文。 但是,它们都使用ActorSystem.actorOf()方法来创建众所周知的昂贵操作的参与者。

ActorSystem system = ctx.getBean(ActorSystem.class);
system.actorOf(.....)

见 - https://github.com/typesafehub/activator-akka-java-spring/blob/master/src/main/java/sample/Main.java

我想使用参与者来处理每个通过身份验证的 Web 请求。使用上面的代码,我最终将为每个不理想的请求创建根参与者。

任何指示将不胜感激。

下面没有回答原始问题,即在请求进入 Web 应用程序时减少通常需要创建的新参与者的数量。

要使用Akka路由器来做到这一点,它可以像以下代码行一样简单:

getContext().actorOf(SpringExtProvider.get(getContext().system()).props("AnotherActor.").withRouter(new RoundRobinPool(100)), "another");

Akka 文档提供了有关配置的更多详细信息,但值得 http://doc.akka.io/docs/akka/snapshot/java/routing.html 查看。最好通过 Akka 配置文件定义它们的行为,而不是硬编码到应用程序中。你可以这样称呼它:

getContext().actorOf(SpringExtProvider.get(getContext().system()).props("AnotherActor.").withRouter(new FromConfig()), "another");

..并在 application.conf 文件中定义路由器的类型和行为。

如果您还没有考虑过,那么还值得一试如何使您的网络任务异步。一种方法是使用 Spring 的延迟结果并将其实例传递给您的 actor,并在搜索请求完成时设置结果。

-

-更新 20/11--

我认为为什么演员选择不适合你是因为你试图使用豆子名称,而不是演员名字作为演员选择的节奏。创建路由器时,您没有指定演员名称,因此 Akka 会在内部为其指定一个名称,类似于"$a"。

举例来说,如果你用以下方法创建你的演员:

actorSystem.actorOf(this.get(actorSystem).props(applicationContext, "bean_name"), "actorName");

然后,您应该能够通过以下方式执行演员选择:

actorSystem.actorSelection("actorName");

或者,要创建上述路由器Actor一次,然后在对Spring MVC Web服务发出的每个请求中重用它,您可以在Spring @Configuration类中创建它,并将ActorRef作为bean公开,以便您可以注入Spring @Controller类。以下是我从内存中创建的快速示例,因此请确保对其进行测试/编译等。

@Configuration
public class Config {
   @Autowired
   private ActorSystem actorSystem;
   @Bean(name = "routerActorRef")
   public ActorRef routerActorRef() { 
      getContext().actorOf(SpringExtProvider.get(actorSystem).props("AnotherActor").withRouter(new RoundRobinPool(100)), "another");
   }
}

然后,您可以通过编写以下内容将其注入另一个 Spring bean 中:

@Autowired
@Qualifier("routerActorRef")
private ActorRef routerActorRef;

应该注意的是,这只对顶级参与者真正可行,对较低级别的参与者是可能的,但要有效管理会变得非常棘手。

--

原答案 --

链接到的 Main 方法中的示例显示了如何创建初始顶级参与者,该参与者将由基于系统的"用户"参与者监督。这是一个非常简单的示例,演示了创建一个名为 CountingActor 的 Spring 托管 actor,其中注入了一个名为 CountingService 的 Spring 托管 Bean。

为了进一步了解此示例,您可以定义另一个看起来类似于 CountingActor 的 actor,例如

@Named("AnotherActor")
@Scope("prototype")
class AnotherActor extends UntypedActor {
  // the service that will be automatically injected
  final AnotherService anotherService;
  @Inject
  public AnotherActor(@Named("AnotherService") AnotherService anotherService) {
    this.anotherService = anotherService;
  }    
  @Override
  public void onReceive(Object message) throws Exception {
    if (message == "doSomething") {
      anotherService.doSomething();
    } else {
      unhandled(message);
    }
  }
}

我假设还有另一个名为 AnotherService 的 Spring 服务 bean,它有一个方法 doSomething(),它将在创建 OtherActor 时注入。

然后在CountingActor中,你可以像这样创建OtherActor:

@Named("CountingActor")
@Scope("prototype")
class CountingActor extends UntypedActor {
  public static class Count {}
  public static class Get {}
  // the service that will be automatically injected
  final CountingService countingService;
  @Inject
  public CountingActor(@Named("CountingService") CountingService countingService) {
    this.countingService = countingService;
  }
  private int count = 0;
  @Override
  public void onReceive(Object message) throws Exception {
    if (message instanceof Count) {
      count = countingService.increment(count);
      // Create AnotherActor here as a child of CountingActor by using the CountingActor's context
      ActorRef anotherActor = getContext().actorOf(SpringExtProvider.get(system).props("AnotherActor"), "another");
      anotherActor.tell("doSomething", getSelf());
    } else if (message instanceof Get) {
      getSender().tell(count, getSelf());
    } else {
      unhandled(message);
    }
  }
}
这里的 actor 创建

与主要的 actor 创建之间的主要区别在于使用 getContext().actorOf(...) 而不是 system.actorOf(...)。使用 getContext() 会导致新参与者被创建为 CounterActor 的子角色,而不是顶级"用户"参与者。

在官方 Akka 文档中对这种行为有很好的描述:http://doc.akka.io/docs/akka/snapshot/java/untyped-actors.html#creating-actors-with-props

最新更新