由于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") 对应
下面是详细代码:
/*
下面是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()); } }
@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); } }