spring boot集成akka

由於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);
  }
}






發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章