Akka处理并发的方法基于Actor模型。在Akka里,Actor之间通信的唯一机制就是消息传递,每个Actor都有一个ActorSystem管理,其中ActorSystem是单例的,它管理了多个actor
家里电脑没装visio,勉强看看就行
下面就介绍下使用Akka来模拟学生向老师提问题的场景
首先得建立工程,scala也可以使用Maven管理,和java一样创建一个Maven项目,然后修改 src/main/java 和 src/test/java 为 src/main/scala 和 src/test/scala,修改pom文件,并且添加scala和akka的依赖包以及scala的编译插件等
项目整个结构如下:
1.Pom文件如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>myScala05</groupId>
<artifactId>myScala05</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.10.6</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-actor_2.10</artifactId>
<version>2.3.14</version>
</dependency>
<dependency>
<groupId>com.typesafe.akka</groupId>
<artifactId>akka-remote_2.10</artifactId>
<version>2.3.14</version>
</dependency>
<dependency>
<groupId>jdk.tools</groupId>
<artifactId>jdk.tools</artifactId>
<version>1.7</version>
<scope>system</scope>
<systemPath>${JAVA_HOME}/lib/tools.jar</systemPath>
</dependency>
</dependencies>
<build>
<sourceDirectory>src/main/scala</sourceDirectory>
<testSourceDirectory>src/test/scala</testSourceDirectory>
<plugins>
<plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>scala-maven-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<goals>
<goal>compile</goal>
<goal>testCompile</goal>
</goals>
<configuration>
<args>
<arg>-make:transitive</arg>
<arg>-dependencyfile</arg>
<arg>${project.build.directory}/.scala_dependencies</arg>
</args>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>reference.conf</resource>
</transformer>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>MyMaster</mainClass>
</transformer>
</transformers>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
2.Teacher.scala类如下:
package com.lijie.scala
import com.typesafe.config.ConfigFactory
import akka.actor.Actor
import akka.actor.ActorSystem
import akka.actor.Props
import akka.actor.actorRef2Scala
/**
* @author lijie
*/
class Teacher extends Actor {
override def preStart(): Unit = {
println("preStart在构造方法执行完后 receive执行之前被调用!")
}
override def receive: Receive = {
case TeacherOnline(name) => {
println(s"$name 上线了,学生可以进行提问")
}
//用来匹配学生上线的消息
case StudentConnect(name) => {
println(s"学生:$name 上线了!!!")
}
//用来匹配学生的计算问题
case Sum(a, b) => {
val sum = a + b
println(s"执行了学生发送的问题 计算$a + $b = $sum")
//返回计算结果
sender ! ResultSum(sum)
}
}
}
object Teacher {
def main(args: Array[String]): Unit = {
val argss = Array[String]("127.0.0.1", "8080")
val host = argss(0)
val port = argss(1).toInt
//配置文件
val conf = s"""
|akka.actor.provider = "akka.remote.RemoteActorRefProvider"
|akka.remote.netty.tcp.hostname = "$host"
|akka.remote.netty.tcp.port = "$port"
""".stripMargin
//创建配置文件对象
val config = ConfigFactory.parseString(conf)
//创建ActorSystem(每个actor都有一个ActorSystem它是单例的,ActorSystem管理多个actor)
val actorSys = ActorSystem("TeacherSys", config)
//创建actor
val teacher = actorSys.actorOf(Props(new Teacher), "Teacher")
//老师上线了
teacher ! TeacherOnline("苍老师")
actorSys.awaitTermination()
}
}
3.Student.scala类如下:
package com.lijie.scala
import com.typesafe.config.ConfigFactory
import akka.actor.Actor
import akka.actor.ActorSelection
import akka.actor.ActorSelection.toScala
import akka.actor.ActorSystem
import akka.actor.Props
import akka.actor.actorRef2Scala
/**
* @author lijie
*/
class Student(val teacherHost: String, val teacherPort: Int, val teacherActorSystem: String, val teacherName: String) extends Actor {
//老师的代理对象
var teacher: ActorSelection = _
override def preStart(): Unit = {
//获取老师的代理对象
teacher = context.actorSelection(s"akka.tcp://$teacherActorSystem@$teacherHost:$teacherPort/user/$teacherName")
//发送学生上线消息
teacher ! StudentConnect("lijie")
}
override def receive: Receive = {
//匹配向老师提问请求
case Sum(a, b) => {
//向老师请求计算a+b
teacher ! Sum(a, b)
}
//匹配老师返回的结果
case ResultSum(sum) => {
println("收到老师的回答,计算结果为:" + sum)
}
}
}
object Student {
def main(args: Array[String]): Unit = {
val argss = Array[String]("127.0.0.1", "8089", "127.0.0.1", "8080", "TeacherSys", "Teacher")
val host = argss(0)
val port = argss(1).toInt
val teacherHost = argss(2)
val teacherPort = argss(3).toInt
val teacherActorSystem = argss(4)
val teacherName = argss(5)
val conf = s"""
|akka.actor.provider = "akka.remote.RemoteActorRefProvider"
|akka.remote.netty.tcp.hostname = "$host"
|akka.remote.netty.tcp.port = "$port"
""".stripMargin
val config = ConfigFactory.parseString(conf)
//创建学生的ActorSystem
val actorSys = ActorSystem("StudentSys", config)
//创建学生的actor对象
val actor = actorSys.actorOf(Props(new Student(teacherHost, teacherPort, teacherActorSystem, teacherName)), "Student")
//请求老师计算
actor ! Sum(1, 2)
actorSys.awaitTermination()
}
}
4.CaseClass.scala类如下:
package com.lijie.scala
import java.io.Serializable
/**
* @author lijie
*/
case class TeacherOnline(name: String) extends Serializable
case class StudentConnect(name: String) extends Serializable
case class MyResult(sum: Int) extends Serializable
case class Sum(a: Int, b: Int) extends Serializable
case class ResultSum(sum: Int) extends Serializable
首先运行Teacher程序:
然后运行Student程序,运行Student之后 老师那边会先收到学生上线的消息,然后收到学生请求计算的消息,最后会返回计算结果给学生:
老师收到学生消息并计算返回
学生请求老师计算并收到结果:
可以分别把老师和学生的程序打包然后部署到不同服务器上面执行,先启动老师然后启动学生,效果一样,这样就模拟了一个 Akka分布式的学生向老师提问题的程序