我想让akka使用spring应用程序.这是一款完全符合akka模型的搜索应用程序.关于此集成的大多数在线示例和类型安全示例都讨论了使用akka扩展来注入spring应用程序上下文.但是,它们都使用ActorSystem.actorOf()方法来创建已知昂贵操作的actor.
ActorSystem system = ctx.getBean(ActorSystem.class);
system.actorOf(.....)
我想使用actor来处理每个通过身份验证的Web请求.使用上面的代码,我将最终为每个不理想的请求创建root actor.
任何指针都会非常感激.
解决方法:
下面没有回答原始问题,这个问题是关于减少通常在请求进入Web应用程序时需要创建的新actor的数量.
要使用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文件中定义路由器的类型和行为.
如果您还没有考虑过它,那么还有必要查看如何使您的Web重新请求异步.一种方法是使用Spring的DeferredResult并将其实例传递给您的actor,并在完成搜索请求时设置结果.
– 更新20 / 11–
我认为为什么演员选择不适合你是因为你试图使用bean名称,而不是演员名称作为演员选择的pacth.在创建路由器时,您没有指定一个actor名称,所以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方法中的示例显示了如何创建初始顶级actor,该actor将由基于系统的“user”actor监督.这是一个非常简单的示例,演示如何创建一个名为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(),它将在创建AnotherActor时注入.
然后在CountingActor中你可以像这样创建AnotherActor:
@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创建和主要的主要区别是使用getContext().actorOf(…)而不是system.actorOf(…).使用getContext()会将新actor创建为CounterActor的子级,而不是顶级“user”actor.