spring boot集成akka

摘要:
本文参考了Akka的官方使用文档,并根据自己的经验和理解提供了Akka和Spring集成解决方案。ActorSystem=ActorSystem.create;然而,对于访问Spring,IOC模式将更加接地气。您可以这样做:然后在需要的地方依赖注入。Greeter是表示问候者的参与者:publicclassGreeterextendsUntypedActor{publicstatenumMsg{GREET,DONE;}@Overridepublicvoid onReceive{if{System.out.println(“Hello World!”为了方便描述与Spring的集成,这里是另一个示例。CountingActor是用于计数的参与者,如代码列表所示。@Named@ScopepublicclassCountingActorextendsUntypedActor{publicstaticassCount{}publicstaticpassGet{}//theservicethatwillbeautomaticallyinjected@ResourceprivateCountingServicecountingService ; privateintcount=0;@Overridepublicvoid onReceivethrowsException{if{count=countingService.exception;}else if{getSender().cell;}other{unhandled;}}CountingActor用于接收计数消息,并接收Get消息以回复发件人的当前计数值。

  本文参考Akka官方使用文档,根据自身的经验和理解,提供Akka与Spring集成的方案。本文不说明Spring框架的具体使用,并从Spring已经配置完备的情况开始叙述。

Actor系统——ActorSystem

       什么是ActorSystem?根据Akka官网的描述——ActorSystem是一个重量级的结构体,可以用于分配1到N个线程,所以每个应用都需要创建一个ActorSystem。通常而言,使用以下代码来创建ActorSystem。

ActorSystem system = ActorSystem.create("Hello");

  不过对于接入Spring而言,由IOC(Inversion of Control,控制反转)方式会更接地气,你可以这样:

    <!-- AKKA System Setup -->
    <bean id="actorSystem" class="akka.actor.ActorSystem" factory-method="create" destroy-method="shutdown" scope="singleton">
        <constructor-arg value="helloAkkaSystem"/>
    </bean>

然后在你需要的地方依赖注入即可。

Actor编程模型

   我们可以通过以下代码(代码片段借用了Akka官网的例子)创建一个简单的Actor例子。

       Greeter是代表问候者的Actor:

public class Greeter extends UntypedActor {
 
  public static enum Msg {
    GREET, DONE;
  }
 
  @Override
  public void onReceive(Object msg) {
    if (msg == Msg.GREET) {
      System.out.println("Hello World!");
      getSender().tell(Msg.DONE, getSelf());
    } else
      unhandled(msg);
  }
 
}

  一般情况下我们的Actor都需要继承自UntypedActor,并实现其onReceive方法。onReceive用于接收消息,你可以在其中实现对消息的匹配并做不同的处理。

  HelloWorld是用于向Greeter发送问候消息的访客:

public class HelloWorld extends UntypedActor {
 
  @Override
  public void preStart() {
    // create the greeter actor
    final ActorRef greeter = getContext().actorOf(Props.create(Greeter.class), "greeter");
    // tell it to perform the greeting
    greeter.tell(Greeter.Msg.GREET, getSelf());
  }
 
  @Override
  public void onReceive(Object msg) {
    if (msg == Greeter.Msg.DONE) {
      // when the greeter is done, stop this actor and with it the application
      getContext().stop(getSelf());
    } else
      unhandled(msg);
  }
}

  有了Actor之后,我们可以这样使用它:

ActorRef a = system.actorOf(Props.create(HelloWorld.class), "helloWorld");

  在HelloWorld的preStart实现中,获取了Greeter的ActorRef(Actor的引用)并向Greeter发送了问候的消息,Greeter收到问候消息后,会先打印Hello World!,然后向HelloWorld回复完成的消息,HelloWorld得知Greeter完成了向世界问好这个伟大的任务后,就结束了自己的生命。HelloWorld的例子用编程API的方式告诉了我们如何使用Actor及发送、接收消息。为了便于描述与Spring的集成,下面再介绍一个例子。

       CountingActor(代码主体借用自Akka官网)是用于计数的Actor,见代码清单所示。

@Named("CountingActor")
@Scope("prototype")
public class CountingActor extends UntypedActor {
 
    public static class Count {
    }
 
    public static class Get {
    }
 
    // the service that will be automatically injected
    @Resource
    private CountingService countingService;
 
    private int count = 0;
 
    @Override
    public void onReceive(Object message) throws Exception {
        if (message instanceof Count) {
            count = countingService.increment(count);
        } else if (message instanceof Get) {
            getSender().tell(count, getSelf());
        } else {
            unhandled(message);
        }
    }
}

  CountingActor用于接收Count消息进行计数,接收Get消息回复给发送者当前的计数值。CountingService是用于计数的接口,其定义如下:

public interface CountingService {
    
    /**
     * 计数
     * @param count
     * @return
     */
    int increment(int count);
 
}

  CountingService的具体实现是CountingServiceImpl,其实现如下:

@Service("countingService")
public class CountingServiceImpl implements CountingService {
 
    private static Logger logger = LoggerFactory.getLogger(CountingServiceImpl.class);
 
    /*
     * (non-Javadoc)
     * 
     * @see com.elong.sentosa.metadata.service.CountingService#increment(int)
     */
    @Override
    public int increment(int count) {
        logger.info("increase " + count + "by 1.");
        return count + 1;
    }
 
}
  CountingActor通过注解方式注入了CountingService,CountingActor的计数实际是由CountingService完成。
        细心的同学可能发现了CountingActor使用了注解Named,这里为什么没有使用@Service或者@Component等注解呢?由于Akka的Actor在初始化的时候必须使用System或者Context的工厂方法actorOf创建新的Actor实例,不能使用构造器来初始化,而使用Spring的Service或者Component注解,会导致使用构造器初始化Actor,所以会抛出以下异常:
akka.actor.ActorInitializationException: You cannot create an instance of [com.elong.metadata.akka.actor.CountingActor] explicitly using the constructor (new). You have to use one of the 'actorOf' factory methods to create a new actor. See the documentation.

  如果我们不能使用@Service或者@Component,也不能使用XML配置的方式使用(与注解一个道理),那么我们如何使用CountingActor提供的服务呢?

IndirectActorProducer接口

        IndirectActorProducer是Akka提供的Actor生成接口,从其名字我们知道Akka给我们指出了另一条道路——石头大了绕着走!通过实现IndirectActorProducer接口我们可以定制一些Actor的生成方式,与Spring集成可以这样实现它,见代码清单所示。

public class SpringActorProducer implements IndirectActorProducer {
    private final ApplicationContext applicationContext;
    private final String actorBeanName;
    private final Object[] args;
 
    public SpringActorProducer(ApplicationContext applicationContext, String actorBeanName, Object ... args) {
        this.applicationContext = applicationContext;
        this.actorBeanName = actorBeanName;
        this.args = args;
    }
 
    public Actor produce() {
        return (Actor) applicationContext.getBean(actorBeanName, args);
    }
 
    public Class<? extends Actor> actorClass() {
        return (Class<? extends Actor>) applicationContext.getType(actorBeanName);
    }
}

  SpringActorProducer的实现主要借鉴了Akka官方文档,我这里对其作了一些扩展以便于支持构造器带有多个参数的情况。从其实现看到实际是利用了ApplicationContext提供的getBean方式实例化Actor。
       这里还有两个问题:一、ApplicationContext如何获取和设置?二、如何使用SpringActorProducer生成Spring需要的Actor实例?

       对于第一个问题,我们可以通过封装SpringActorProducer并实现ApplicationContextAware接口的方式获取ApplicationContext;对于第二个问题,我们知道Akka中的所有Actor实例都是以Props作为配置参数开始的,这里以SpringActorProducer为代理生成我们需要的Actor的Props。

       SpringExt实现了以上思路,见代码清单所示。

@Component("springExt")
public class SpringExt implements Extension, ApplicationContextAware {
 
    private ApplicationContext applicationContext;
 
    /**
     * Create a Props for the specified actorBeanName using the
     * SpringActorProducer class.
     *
     * @param actorBeanName
     *            The name of the actor bean to create Props for
     * @return a Props that will create the named actor bean using Spring
     */
    public Props props(String actorBeanName, Object ... args) {
        return Props.create(SpringActorProducer.class, applicationContext, actorBeanName, args);
    }
 
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

应用例子

        经过了以上的铺垫,现在你可以使用创建好的CountingActor了,首先你需要在你的业务类中注入ActorSystem和SpringExt。

    @Autowired
    private ActorSystem actorSystem;
 
    @Autowired
    private SpringExt springExt;

  然后我们使用CountingActor进行计数,代码如下:

    ActorRef counter = actorSystem.actorOf(springExt.props("CountingActor"), "counter");
 
    // Create the "actor-in-a-box"
        final Inbox inbox = Inbox.create(system);
        
    // tell it to count three times
        inbox.send(counter, new Count());
        inbox.send(counter, new Count());
        inbox.send(counter, new Count());
 
    // print the result
    FiniteDuration duration = FiniteDuration.create(3, TimeUnit.SECONDS);
    Future<Object> result = ask(counter, new Get(), Timeout.durationToTimeout(duration));
    try {
        System.out.println("Got back " + Await.result(result, duration));
    } catch (Exception e) {
        System.err.println("Failed getting result: " + e.getMessage());
        throw e;
    }

输出结果为:

Got back 3

总结

       本文只是最简单的Akka集成Spring的例子,Akka的remote、cluster、persistence、router等机制都可以应用。

转载来源:https://blog.csdn.net/beliefer/article/details/53783936

免责声明:文章转载自《spring boot集成akka》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇2、架构设计 --短信平台开发C# 消息处理机制及自定义过滤方式下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

WebService与CXF

一:Webservice  1:WebService是干什么的?有什么用? 一言以蔽之:WebService是一种跨编程语言和跨操作系统平台的远程调用规范。 比如,amazon,天气预报系统,淘宝网,校内网,百度等把自己的系统服务以webservice服务的形式暴露出来,让第三方网站和程序可以调用这些服务功能,这样扩展了自己系统的市场占有率 从表面上看,W...

SpringBoot入门教程(一) SpringBoot入门

一、SpringBoot简介   SpringBoot是整个Spring技术栈的整合,来简化Spring应用开发,约定大于配置,去繁从简,just run 就能创建一个独立的,产品级别的应用。   背景:     J2EE笨重的开发、繁多的配置、底下的开发效率、复杂的部署流程、第三方技术集成难度大。   解决:     "Spring全家桶"时代。   ...

SpringBoot与动态多数据源切换

本文简单的介绍一下基于SpringBoot框架动态多数据源切换的实现,采用主从配置的方式,配置master、slave两个数据库。 一、配置主从数据库 spring: datasource: type: com.alibaba.druid.pool.DruidDataSource driverClassName:...

SpringBoot(3):SpringData 数据访问

一. 简介 Spring Data是一个用于简化数据库访问,并支持云服务的开源框架;其主要目标是 使得对数据的访问变得方便快捷。对于数据访问层,无论是 SQL(关系型数据库) 还是 NOSQL(非关系型数据库)。Spring Boot 底层都是采用 Spring Data 的方式进行统一处理各种数据库 Sping Data 官网:https://spri...

SpringBoot整合Mybatis,TypeAliases配置失败的问题

SpringBoot整合Mybatis,TypeAliases配置失败的问题 问题描述 在应用MyBatis时,使用对象关系映射,将对象和Aliase映射起来。 在Mybatis的文档明确写出,如果你没有明确定义实体类的Aliase,框架会自动将Class Name自动 作为别名。 那么问题来了,当使用java -jar xxx.jar&启动的时候...

spring boot jpa

spring boot jpa 访问数据库的方式一般来说有两种,一种以Java Entity为中心,将实体和实体关系对应到数据库的表和表关系,例如Hibernate框架(Spring Data JPA由此实现);另一种以原生SQL为中心,更加灵活便捷,例如Mybatis。这里重点介绍下Spring Data JPA技术。 spring boot jpa介绍...