1、Akka简介&常用API介绍

Akka简介

Akka是Java虚拟机平台上构建高并发、分布式和容错应用的工具包。Akka用Scala语言编写,同时提供了Scala和Java的开发接口。

Akka可以以两种不同的方式来使用

  • 以库的形式:在web应用中使用,放到 WEB-INF/lib 中或者作为一个普通的Jar包放进classpath。
  • 以微内核的形式:你可以将应用放进一个独立的内核。自己有一个main类来初始化Actor系统。

Akka几大特性

  1. 易于构建并行和分布式应用 (Simple Concurrency & Distribution)

    Akka在设计时采用了异步通讯和分布式架构,并对上层进行抽象,如Actors、Futures ,STM等。

  2. 容错性(Resilient by Design)

    系统具备自愈能力,在本地/远程都有监护。

  3. 高性能(High Performance)

    在单机中每秒可发送50000000个消息。内存占用小,1GB内存中可保存2500000个actors。

  4. 弹性,无中心(Elastic — Decentralized)

    自适应的负责均衡,路由,分区,配置

  5. 伸缩性(Extensible)

    可以使用Akka 扩展包进行扩展。

在Akka的世界里,只有一个内容需要学习和管理,具有高内聚和高一致的语义。Akka是一种高度可扩展的软件,这不仅仅表现在性能方面,也表现在它所适用的应用的大小。Akka的核心,Akka-actor是非常小的,可以非常方便地放进你的应用中,提供你需要的异步无锁并行功能,不会有任何困扰。你可以任意选择Akka的某些部分集成到你的应用中,也可以使用完整的包——Akka 微内核,它是一个独立的容器,可以直接部署你的Akka应用。随着CPU核数越来越多,即使你只使用一台电脑,Akka也可作为一种提供卓越性能的选择。Akka还同时提供多种并发范型,允许用户选择正确的工具来完成工作。

Akka简单使用

使用IDEA+Maven构建Akka开发环境。

  1. 导入Maven依赖

    <properties>
            <maven.compiler.source>1.8</maven.compiler.source>
            <maven.compiler.target>1.8</maven.compiler.target>
            <encoding>UTF-8</encoding>
            <scala.version>2.11.8</scala.version>
            <scala.compat.version>2.11</scala.compat.version>
            <akka.version>2.3.6</akka.version>
        </properties>
    
        <dependencies>
            <!-- 添加scala的依赖 -->
            <dependency>
                <groupId>org.scala-lang</groupId>
                <artifactId>scala-library</artifactId>
                <version>${
          
          scala.version}</version>
            </dependency>
            <!-- 添加akka的actor依赖 -->
            <dependency>
                <groupId>com.typesafe.akka</groupId>
                <artifactId>akka-actor_${
          
          scala.compat.version}</artifactId>
                <version>${
          
          akka.version}</version>
            </dependency>
            <!-- 多进程之间的Actor通信 -->
            <dependency>
                <groupId>com.typesafe.akka</groupId>
                <artifactId>akka-remote_${
          
          scala.compat.version}</artifactId>
                <version>${
          
          akka.version}</version>
            </dependency>
        </dependencies>
    
  2. Java实现Actor Demo

    /**
     * @author li.pan
     * @version 1.0.0
     * @Description TODO
     * @createTime 2020年12月22日 20:18:00
     */
    public class JavaPongActor extends AbstractActor {
          
          
    
        /**
         * AbstractActor 类有一个 receive 方法,其子类必须实现这个方法或是通过构造函数调用该方法。
         *
         * @return 返回的类型是PartialFunction(偏函数), 这个类型来自Scala API。在Java中
         * Akka为我们提供了一个抽象的构造方法类ReceiveBuilder,用于生成 PartialFunction 作为返回值。
         */
        @Override
        public PartialFunction receive() {
          
          
            return ReceiveBuilder
                    // matchEquals和matchAny用来匹配消息
                    .matchEquals("Ping", s ->
                            sender().tell("Pong", ActorRef.noSender()))
                    .match(String.class, s ->
                            System.out.println("It's a string: " + s))
                    .matchAny(x ->
                            sender().tell(
                                    new Status.Failure(new Exception("unknown message")), self()))
                    .build();
        }
    }
    

    上述Java代码展示了如何使用Akka中对应的Java API,每一个具体的API含义如下:

    方法 含义
    Receive AbstractActor 类有一个 receive 方法,其子类必须实现这个方法或是通过构造函数调用该方法。 receive 方法返回的类型是 PartialFunction, 这个类型来自 Scala API。在 Java 中,并没有提供任何原生方法来构造 Scala 的 PartialFunction(偏函数) ,因此 Akka 为我们提供了一个抽象的构造方法类
    ReceiveBuilder 主要是用Build方法返回PartialFunction
    Match 类似于Scala中的模式匹配,用于消息的匹配:
    match(class, function):描述了对于任何尚未匹配的该类型的示例,应该如何响应。
    match(String.class, s -> {if(s.equals("Ping")) respondToPing(s);})
    match(class, predicate, function):描述了对于 predicate 条件函数为真的某特定类型的消息,应该如何响应。
    match(String.class, s -> s.equals("Ping"), s -> respondToPing(s))
    matchEquals(object, function):描述了对于和传入的第一个参数相等的消息,应该如何响应。
    matchEquals("Ping", s -> respondToPing(s))
    matchAny(function):该函数匹配所有尚未匹配的消息。通常来说,最佳实践是返回错误信息,或者至少将错误信息记录到日志,帮助开发过程中的错误调试。
    Sender 返回所收到的消息的响应,响应的对象既可能是一个 Actor,也可能是来自于 Actor 系统外部的请求。
    Tell sender()函数会返回一个 ActorRef。 在上面的例子中, 我们调用了 sender().tell()。tell()是最基本的单向消息传输模式。 第一个参数是我们想要发送至对方信箱的消息。第二个参数则是希望对方 Actor 看到的发送者。
    Ask 向 Actor 发送一条消息,返回一个 Future。当 Actor 返回响应时,会完成Future。不会向消息发送者的邮箱返回任何消息。
    Forward 将接收到的消息再发送给另一个 Actor。所有发送至 sender()的响应都会返回给原始消息的发送者。
    Pipe 用于将 Future 的结果返回给 sender()或另一个 Actor。如果正在使用 Ask 或是处理一个 Future,那么使用 Pipe 可以正确地返回 Future 的结果。
  3. Scala实现Actor Demo

    class ScalaPongActor extends Actor {
          
          
      override def receive: Receive = {
          
          
        case "Ping" => sender() ! "Pong"
        case _ => sender() ! Status.Failure(new Exception("unknown message"))
      }
    }
    

    以上代码使用Scala语言实现了一个简单的Actor,其API大部分含义和Java中雷同,有一些在使用上不同如下:

    方法 含义
    Receive 在 Actor 中重写基类的 receive 方法。并且返回一个 PartialFunction。要注意的是,receive 方法的返回类型是 Receive。Receive 只不过是定义的一种类型, 表示 scala.PartialFunction[scala.Any, scala.Unit]。
    Sender 返回所收到的消息的响应,响应的对象既可能是一个 Actor,也可能是来自于 Actor 系统外部的请求。
    ! 在 Scala 中,通过“! ”来调用 tell 方法。在 Scala 中,消息发送者是隐式传入的,因此我们不需要再显式传入消息发送者的引用。在 tell 方法“!”的方法签名中,有一个隐式的 ActorRef 参数。如果在 Actor 外部调用 tell 方法的话,该参数的默认值会设为 noSender。下面就是该方法的签名:
    def !(message: Any)(implicit sender: ActorRef = Actor.noSender): Unit
    ? “?”在scala代表的是ask。
    Failure 在收到未知消息时,返回akka.actor.Status.Failure。Actor 本身在任何情况下都不会自己返回 Failure(即使Actor 本身出现错误) 。 因此如果想要将发生的错误通知消息发送者, 那么我们必须要主动发送一个 Failure 给对方。 发送回 Failure 会导致请求方的 Future 被标记为失败。

    另外需要注意的是,在Scala中Actor 中有一个隐式的变量 self, Actor 通过 self 得到消息发送者的值。 因此 Actor 中 tell 方法的消息发送者永远是 self。

    implicit final val self = context.self
    

关注公众号 数据工匠记 ,专注于大数据领域离线、实时技术干货定期分享!个人网站 www.lllpan.top
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/lp284558195/article/details/111567913