由於Akka的Actor在初始化的時候必須使用System或者Context的工廠方法actorOf創建新的Actor實例,不能使用構造器來初始化,而使用Spring的Service或者Component註解,會導致使用構造器初始化Actor,所以會拋出以下異常:
akka.actor.ActorInitializationException: You cannot create an instance of [com.jikuan.zjk.akka.actor.TestActor]
explicitly using the constructor (new). You have to use one of the 'actorOf' factory methods to create a new actor.
See the documentation.
真正想用註解方式加載akka類其實用處不大,最大的是想在akka actor類中加載寫的其他的service時候,無法使用註解,但是你的service又都是註解寫的,這個就比較噁心,所以還是要想辦法將akka集成,這樣就可以像使用spring一樣使用akka了,下面是具體的做法: 參考:https://www.linkedin.com/pulse/spring-boot-akka-part-1-aliaksandr-liakh
1.構建SpringActorProducer類
import org.springframework.context.ApplicationContext;
import akka.actor.Actor;
import akka.actor.IndirectActorProducer;
/*
* jikuan.zjk
*/
public class SpringActorProducer implements IndirectActorProducer {
final private ApplicationContext applicationContext;
final private String actorBeanName;
public SpringActorProducer(ApplicationContext applicationContext, String actorBeanName) {
this.applicationContext = applicationContext;
this.actorBeanName = actorBeanName;
}
@Override
public Actor produce() {
return (Actor) applicationContext.getBean(actorBeanName);
}
@Override
public Class<? extends Actor> actorClass() {
return (Class<? extends Actor>) applicationContext.getType(actorBeanName);
}
}
2.構建SpringExtension類
package com.alibaba.dbtech.paas.app.adha.akka;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import akka.actor.Extension;
import akka.actor.Props;
/*
* jikuan.zjk
*/
@Component("springExtension")
public class SpringExtension implements Extension {
private ApplicationContext applicationContext;
public void initialize(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
public Props props(String actorBeanName) {
return Props.create(SpringActorProducer.class, applicationContext, actorBeanName);
}
}
3.創建bean
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.typesafe.config.Config;
import com.typesafe.config.ConfigFactory;
import akka.actor.ActorSystem;
/*
* jikuan.zjk
*/
@Configuration
public class AkkaConfig {
@Autowired
private ApplicationContext applicationContext;
@Autowired
private SpringExtension springExtension;
@Bean
public ActorSystem actorSystem() {
ActorSystem actorSystem = ActorSystem.create("ActorSystem");
springExtension.initialize(applicationContext);
return actorSystem;
}
@Bean
public Config akkaConfiguration() {
return ConfigFactory.load();
}
}
4.創建actor
@Autowired
AdhaHeartbeatService adhaHeartbeatService;
可以直接像上面那樣加載自己的service了
@Autowired
private ActorSystem actorSystem;
@Autowired
private SpringExtension springExtension;
像spring一樣加載ActorSystem
ActorRef routerActorRef =
actorSystem.actorOf(springExtension.props("detectActor2").withDispatcher("detect-dispatcher")
.withRouter(new SmallestMailboxPool(50000)), "detectRouterActor");
創建actor方式如上,上面是項目中使用獨立Dispatcher和router的例子,簡單的使用可以使用下面的創建方式
ActorRef routerActorRef =
actorSystem.actorOf(springExtension.props("detectActor2"), "detectRouterActor");
其中detectActor2是你在DetectActor2 Actor上使用@Component("detectActor2")
對應
下面是詳細代碼:
/*
* AdhaDetect class, single thread task jikuan.zjk
*/
@RestController
public class AdhaAkkaDetect2 extends Detect {
@Autowired
AdhaHeartbeatService adhaHeartbeatService;
@Autowired
AdhaMetaTask adhaMetaTask;
@Autowired
private ActorSystem actorSystem;
@Autowired
private SpringExtension springExtension;
public void detect(String detectStatus, int detectCount) {
ActorRef routerActorRef =
actorSystem.actorOf(springExtension.props("detectActor2").withDispatcher("detect-dispatcher")
.withRouter(new SmallestMailboxPool(50000)), "detectRouterActor");
System.out.println("into detect function,resultActorRef=" + resultActorRef.path());
routerActorRef.tell(new MapMessage(instance, connectMap), ActorRef.noSender());
}
}
下面是DetectActor2代碼
@Component("detectActor2")
@Scope("prototype")
public class DetectActor2 extends AbstractActor {
public PartialFunction receive() {
return ReceiveBuilder.match(String.class, s -> {
System.out.printf("get %s\n" , s);
sender().tell("Hi", self());
}).matchAny(x -> {
System.out.printf("I dont know what you see in DetectActor,%s", getContext().self().path());
sender().tell(new Status.Failure(new Exception("I dont know what you see")), self());
}).build();
}
public static Props props(String response) {
return Props.create(DetectActor2.class, response);
}
}