Akka学习笔记 | hello world

本示例来自于官方示例(https://developer.lightbend.com/start/?group=akka&project=akka-quickstart-java): 
下载后解压打开

注意:新版本的akka需要使用jdk8

一、项目运行

目录结构:

Akka学习笔记 | hello world_第1张图片

AkkaQuickstart 类:

package com.lightbend.akka.sample;

import java.io.IOException;

import com.lightbend.akka.sample.Greeter.Greet;
import com.lightbend.akka.sample.Greeter.WhoToGreet;

import akka.actor.ActorRef;
import akka.actor.ActorSystem;

public class AkkaQuickstart {
  public static void main(String[] args) {
    //首先,main该类创建一个akka.actor.ActorSystemActors运行的容器。
    //接下来,它创建一个Greeter Actor的三个实例和一个Printer Actor的实例。
    final ActorSystem system = ActorSystem.create("helloakka");
    try {
      //#create-actors
      //该actorOf工厂方法创建actor和采用两个参数,称为配置对象Props和一个名称。
      final ActorRef printerActor = 
        system.actorOf(Printer.props(), "printerActor");
      final ActorRef howdyGreeter = 
        system.actorOf(Greeter.props("Howdy", printerActor), "howdyGreeter");
      final ActorRef helloGreeter = 
        system.actorOf(Greeter.props("Hello", printerActor), "helloGreeter");
      final ActorRef goodDayGreeter = 
        system.actorOf(Greeter.props("Good day", printerActor), "goodDayGreeter");
      //#create-actors

      //#main-send-messages
      howdyGreeter.tell(new WhoToGreet("Akka"), ActorRef.noSender());
      howdyGreeter.tell(new Greet(), ActorRef.noSender());

      howdyGreeter.tell(new WhoToGreet("Lightbend"), ActorRef.noSender());
      howdyGreeter.tell(new Greet(), ActorRef.noSender());

      helloGreeter.tell(new WhoToGreet("Java"), ActorRef.noSender());
      helloGreeter.tell(new Greet(), ActorRef.noSender());

      goodDayGreeter.tell(new WhoToGreet("Play"), ActorRef.noSender());
      goodDayGreeter.tell(new Greet(), ActorRef.noSender());
      //#main-send-messages

      System.out.println(">>> Press ENTER to exit <<<");
      System.in.read();
    } catch (IOException ioe) {
    } finally {
      system.terminate();
    }
  }
}
Greeter类:
package com.lightbend.akka.sample;

import akka.actor.AbstractActor;
import akka.actor.ActorRef;
import akka.actor.Props;
import com.lightbend.akka.sample.Printer.Greeting;

//#greeter-messages
public class Greeter extends AbstractActor {
//#greeter-messages
  static public Props props(String message, ActorRef printerActor) {
    return Props.create(Greeter.class, () -> new Greeter(message, printerActor));
  }

  //#greeter-messages
  static public class WhoToGreet {
    public final String who;

    public WhoToGreet(String who) {
        this.who = who;
    }
  }

  static public class Greet {
    public Greet() {
    }
  }
  //#greeter-messages

  private final String message;
  private final ActorRef printerActor;
  private String greeting = "";

  public Greeter(String message, ActorRef printerActor) {
    this.message = message;
    this.printerActor = printerActor;
  }

  @Override
  public Receive createReceive() {
    return receiveBuilder()
        .match(WhoToGreet.class, wtg -> {
          this.greeting = message + ", " + wtg.who;
        })
        .match(Greet.class, x -> {
          //#greeter-send-message
          printerActor.tell(new Greeting(greeting), getSelf());
          //#greeter-send-message
        })
        .build();
  }
//#greeter-messages
}
//#greeter-messages
Printer类:
package com.lightbend.akka.sample;

import akka.actor.AbstractActor;
import akka.actor.Props;
import akka.event.Logging;
import akka.event.LoggingAdapter;

//#printer-messages
public class Printer extends AbstractActor {
//#printer-messages
  static public Props props() {
    return Props.create(Printer.class, () -> new Printer());
  }

  //#printer-messages
  static public class Greeting {
    public final String message;

    public Greeting(String message) {
      this.message = message;
    }
  }
  //#printer-messages

  private LoggingAdapter log = Logging.getLogger(getContext().getSystem(), this);

  public Printer() {
  }

  @Override
  public Receive createReceive() {
    return receiveBuilder()
        .match(Greeting.class, greeting -> {
            log.info(greeting.message+" ( ̄▽ ̄)~*");
        })
        .build();
  }
//#printer-messages
}
//#printer-messages

运行main方法,控制台输出:

Akka学习笔记 | hello world_第2张图片

输入enter停止程序。
 

二、说明

定义Actor和消息

消息可以是任意类型(任何子类型Object)。可以发送盒装原始值(如StringIntegerBoolean作为消息等)以及纯数据结构如数组和集合类型。

Hello World Actors使用三种不同的消息:

  • WhoToGreet:问候的收件人
  • Greet:执行问候语的指令
  • Greeting:包含问候语的消息

在定义Actors及其消息时,请记住以下建议:

  • 由于消息是Actor的公共API,因此定义具有良好名称和丰富语义和域特定含义的消息是一种很好的做法,即使它们只是包装您的数据类型。这样可以更容易地使用,理解和调试基于actor的系统。

  • 消息应该是不可变的,因为它们在不同的线程之间共享。

  • 将actor的关联消息作为静态类放在Actor的类中是一种很好的做法。这使得更容易理解actor期望和处理的消息类型。

  • props在Actor的类中使用静态方法描述如何构造Actor 也是一种常见的模式。

让我们看看Actor如何实现GreeterPrinter演示这些最佳实践。

来自Greeter.java实现

让我们分解一下功能:

  • Greeter类扩展akka.actor.AbstractActor类并实现createReceive方法。
  • 所述Greeter构造函数接受两个参数:String message,这将构建问候消息时和使用ActorRef printerActor,这对演员处理问候的输出的参考。
  • receiveBuilder定义的行为; Actor如何对收到的不同消息做出反应。访问或改变Actor的内部状态是完全线程安全的,因为它受Actor模型的保护。该createReceive方法应该处理actor期望的消息。在这种情况下Greeter,它需要两种类型的消息:WhoToGreetGreet。前者将更新greetingActor 的状态,后者将触发发送greetingPrinterActor。
  • greeting变量包含Actor的状态,默认设置为""
  • 静态props方法创建并返回一个Props实例。Props是一个配置类,用于指定创建actor的选项,将其视为不可变且因此可自由共享的配方,用于创建可包含关联部署信息的actor。此示例仅传递Actor在构造时所需的参数。我们将props在本教程后面看到该方法的实际应用。

Printer actor

Printer实现非常简单:

  • 它创建了一个记录器Logging.getLogger(getContext().getSystem(), this);。通过这样做,我们可以log.info()在没有任何额外布线的情况下写入Actor。
  • 它只处理一种类型的消息Greeting,并记录该消息的内容。

创建actor

在Akka中,您无法使用new关键字创建Actor的实例。相反,您使用工厂创建Actor实例。工厂不返回一个actor实例,而是一个akka.actor.ActorRef指向actor实例的引用。这种间接级别在分布式系统中增加了很多功能和灵活性。。

Akka actor系统

akka.actor.ActorSystem工厂是,在一定程度上,类似于Spring的BeanFactory。它充当actor的容器并管理他们的生命周期。该actorOf工厂方法创建actor和采用两个参数,称为配置对象Props和一个名称。

actor和ActorSystem名字在Akka很重要。例如,您可以将它们用于查找。使用与您的域模型一致的有意义的名称可以更轻松地推断它们。

请注意以下事项:

  • 创建Actor 的actorOf方法。正如我们在上一个主题中讨论的那样,它使用类的静态方法来获取值。提供对新创建的Actor实例的引用。ActorSystemPrinterpropsPrinterPropsActorRefPrinter
  • 因为Greeter,代码创建了三个Actor实例,每个实例都有一个特定的问候消息。

注意:在此示例中,GreeterActors都使用相同的Printer实例,但我们可以创建PrinterActor的多个实例。该示例使用一个来说明消息传递的一个重要概念,我们将在稍后介绍。

接下来,让我们看看如何与actor沟通。

异步通信

actor是被动的和消息驱动的。在收到消息之前,Actor不会执行任何操作。Actor使用异步消息进行通信。这可确保发件人不会等待收件人处理其邮件。相反,发件人将邮件放在收件人的邮箱中,并可以自由地执行其他工作。Actor的邮箱本质上是一个带有排序语义的消息队列。保留从同一个Actor发送的多个消息的顺序,但可以与另一个Actor发送的消息交错。

您可能想知道Actor在处理消息时正在做什么,即做实际的工作?它处于挂起状态,除了内存之外它不消耗任何资源。再次,展示了Actors的轻量级,高效性。

将消息发送给Actor

要将消息放入Actor的邮箱,请使用该tell方法ActorRef。例如,Hello World的主类将消息发送到GreeterActor

Greeter演员也将消息发送给Printer

我们研究了如何创建演员和发送消息。现在,我们来看一下整个Main课程。

主类

MainHello World中的类创建并控制actor。注意使用a ActorSystem作为容器和actorOf创建Actors 的方法。最后,该类创建要发送给Actors的消息。

你可能感兴趣的:(框架)