Akka源码分析-Remote-Actor创建
在之前的博客中,我们分析过local模式下Actor的创建过程,最终还是调用了provider的actorOf的函数创建了Actor,在remote模式下provider就是RemoteActorRefProvider,所以这样就知道在哪里最终创建了Actor。
def actorOf(system: ActorSystemImpl, props: Props, supervisor: InternalActorRef, path: ActorPath,
systemService: Boolean, deploy: Option[Deploy], lookupDeploy: Boolean, async: Boolean): InternalActorRef =
if (systemService) local.actorOf(system, props, supervisor, path, systemService, deploy, lookupDeploy, async)
else { if (!system.dispatchers.hasDispatcher(props.dispatcher))
throw new ConfigurationException(s"Dispatcher [${props.dispatcher}] not configured for path $path") /*
* This needs to deal with “mangled” paths, which are created by remote
* deployment, also in this method. The scheme is the following:
*
* Whenever a remote deployment is found, create a path on that remote
* address below “remote”, including the current system’s identification
* as “sys@host:port” (typically; it will use whatever the remote
* transport uses). This means that on a path up an actor tree each node
* change introduces one layer or “remote/scheme/sys@host:port/” within the URI.
*
* Example:
*
* akka.tcp://sys@home:1234/remote/akka/sys@remote:6667/remote/akka/sys@other:3333/user/a/b/c
*
* means that the logical parent originates from “akka.tcp://sys@other:3333” with
* one child (may be “a” or “b”) being deployed on “akka.tcp://sys@remote:6667” and
* finally either “b” or “c” being created on “akka.tcp://sys@home:1234”, where
* this whole thing actually resides. Thus, the logical path is
* “/user/a/b/c” and the physical path contains all remote placement
* information.
*
* Deployments are always looked up using the logical path, which is the
* purpose of the lookupRemotes internal method.
*/ @scala.annotation.tailrec
def lookupRemotes(p: Iterable[String]): Option[Deploy] = {
p.headOption match {
case None ⇒ None
case Some("remote") ⇒ lookupRemotes(p.drop(3))
case Some("user") ⇒ deployer.lookup(p.drop(1))
case Some(_) ⇒ None
}
} val elems = path.elements
val lookup =
if (lookupDeploy)
elems.head match {
case "user" | "system" ⇒ deployer.lookup(elems.drop(1))
case "remote" ⇒ lookupRemotes(elems)
case _ ⇒ None
}
else None val deployment = {
deploy.toList ::: lookup.toList match {
case Nil ⇒ Nil
case l ⇒ List(l reduce ((a, b) ⇒ b withFallback a))
}
} Iterator(props.deploy) ++ deployment.iterator reduce ((a, b) ⇒ b withFallback a) match {
case d @ Deploy(_, _, _, RemoteScope(address), _, _) ⇒
if (hasAddress(address)) {
local.actorOf(system, props, supervisor, path, false, deployment.headOption, false, async)
} else if (props.deploy.scope == LocalScope) {
throw new ConfigurationException(s"configuration requested remote deployment for local-only Props at [$path]")
} else try {
try {
// for consistency we check configuration of dispatcher and mailbox locally
val dispatcher = system.dispatchers.lookup(props.dispatcher)
system.mailboxes.getMailboxType(props, dispatcher.configurator.config)
} catch {
case NonFatal(e) ⇒ throw new ConfigurationException(
s"configuration problem while creating [$path] with dispatcher [${props.dispatcher}] and mailbox [${props.mailbox}]", e)
}
val localAddress = transport.localAddressForRemote(address)
val rpath = (RootActorPath(address) / "remote" / localAddress.protocol / localAddress.hostPort / path.elements).
withUid(path.uid)
new RemoteActorRef(transport, localAddress, rpath, supervisor, Some(props), Some(d))
} catch {
case NonFatal(e) ⇒ throw new IllegalArgumentException(s"remote deployment failed for [$path]", e)
} case _ ⇒
local.actorOf(system, props, supervisor, path, systemService, deployment.headOption, false, async)
}
}
上面的代码很多,简单起见,先只分析最后一段代码,即使lookupRemotes这个函数也非常重要。最后一段代码的逻辑是根据配置信息判断最终是创建本地actor还是远程actor(也就是RemoteActorRef)。其实这一点还是有点不好理解的,怎么绕来绕去还是用LocalActorRef创建了actor呢?其实关于这一点,我们还需要从官网的文档找到一些细节。官网原文如下:
If you want to use the creation functionality in Akka remoting you have to further amend the application.conf
file in the following way (only showing deployment section):
akka {
actor {
deployment {
/sampleActor {
remote = "akka.tcp://sampleActorSystem@127.0.0.1:2553"
}
}
}
}
The configuration above instructs Akka to react when an actor with path /sampleActor
is created, i.e. using system.actorOf(Props(...), "sampleActor")
. This specific actor will not be directly instantiated, but instead the remote daemon of the remote system will be asked to create the actor, which in this sample corresponds to sampleActorSystem@127.0.0.1:2553
.
Once you have configured the properties above you would do the following in code:
-
val actor = system.actorOf(Props[SampleActor], "sampleActor")
actor ! "Pretty slick"
The actor class SampleActor
has to be available to the runtimes using it, i.e. the classloader of the actor systems has to have a JAR containing the class.
这句话的意思大概是,你可以指定某个actor在远程节点创建!感觉真是神一样的操作!仅仅通过配置就能实现!至少我看到这段说明的时候,感到有点不可思议。当然前提是对应的Actor类能够在远程加载到,也就是包含该类的jar在远程被加载过。这就是RemoteActorRef存在的意义。
分析到这里我们发现,remote模式下,actor的创建基本都转发给了LocalActorRef,那么这样创建的actor能够跨网络传输吗。其实我们仔细思考一下大概就明白了,不管是什么模式创建的actor,一定会有一个本地actor的。毕竟我们发消息的代码都在本地,这就必须有一个本地ActorRef实例。如果要跨网络发消息,就必须拿到远程Actor的ActorRef,而ActorRef我们知道是可以序列化后跨网络传输的,获取到了远程的ActorRef,就可以发远程消息了。至于远程部署Actor,其实也就是在本地创建了一个特殊的Actor(RemoteActorRef、ReliableDeliverySupervisor)作为代理,把消息通过对应的网络对象转发到远程而已。关于这一点我们后面再分析。
remote模式下,Actor的创建也就基本结束了,我们发现,这个跟local模式下的大概流程差别也不是很大,只是维护了与网路相关的对象。不过正是这些网络对象,使得我们可以给远程actor发消息。
Akka源码分析-Remote-Actor创建的更多相关文章
- dubbo源码分析1-reference bean创建
dubbo源码分析1-reference bean创建 dubbo源码分析2-reference bean发起服务方法调用 dubbo源码分析3-service bean的创建与发布 dubbo源码分 ...
- Akka源码分析-Actor创建(续)
在上一遍博客中,我们已经分析了actor创建的大致过程,但只是涉及到了Dipatcher/Mailbox/ActorCell/InternalActorRef等对象的创建,并没有介绍我们自定义的继承A ...
- Akka源码分析-Cluster-Singleton
akka Cluster基本实现原理已经分析过,其实它就是在remote基础上添加了gossip协议,同步各个节点信息,使集群内各节点能够识别.在Cluster中可能会有一个特殊的节点,叫做单例节点. ...
- Akka源码分析-Persistence
在学习akka过程中,我们了解了它的监督机制,会发现actor非常可靠,可以自动的恢复.但akka框架只会简单的创建新的actor,然后调用对应的生命周期函数,如果actor有状态需要回复,我们需要h ...
- Akka源码分析-local-DeathWatch
生命周期监控,也就是死亡监控,是akka编程中常用的机制.比如我们有了某个actor的ActorRef之后,希望在该actor死亡之后收到响应的消息,此时我们就可以使用watch函数达到这一目的. c ...
- Akka源码分析-Cluster-ActorSystem
前面几篇博客,我们依次介绍了local和remote的一些内容,其实再分析cluster就会简单很多,后面关于cluster的源码分析,能够省略的地方,就不再贴源码而是一句话带过了,如果有不理解的地方 ...
- Akka源码分析-Akka-Streams-概念入门
今天我们来讲解akka-streams,这应该算akka框架下实现的一个很高级的工具.之前在学习akka streams的时候,我是觉得云里雾里的,感觉非常复杂,而且又难学,不过随着对akka源码的深 ...
- Akka源码分析-Cluster-Metrics
一个应用软件维护的后期一定是要做监控,akka也不例外,它提供了集群模式下的度量扩展插件. 其实如果读者读过前面的系列文章的话,应该是能够自己写一个这样的监控工具的.简单来说就是创建一个actor,它 ...
- Akka源码分析-Cluster-Distributed Publish Subscribe in Cluster
在ClusterClient源码分析中,我们知道,他是依托于“Distributed Publish Subscribe in Cluster”来实现消息的转发的,那本文就来分析一下Pub/Sub是如 ...
- Akka源码分析-Akka Typed
对不起,akka typed 我是不准备进行源码分析的,首先这个库的API还没有release,所以会may change,也就意味着其概念和设计包括API都会修改,基本就没有再深入分析源码的意义了. ...
随机推荐
- HTTP服务和APACHE
HTTP服务和APACHE 1. 跨Internet的主机间通讯 要通过Internet进行通信,至少需要一对套接字:其中一个运行在客户端,定义了一个唯一的客户进程,称之为ClientSocket,另 ...
- codevs3730 无线网络发射选址
题目描述 Description 随着智能手机的日益普及,人们对无线网的需求日益增大.某城市决定对城市内的公共场所覆盖无线网. 假设该城市的布局为由严格平行的129条东西向街道和129条南北向街道所形 ...
- 9、Java并发性和多线程-线程安全与共享资源
以下内容转自http://ifeve.com/thread-safety/: 允许被多个线程同时执行的代码称作线程安全的代码.线程安全的代码不包含竞态条件.当多个线程同时更新共享资源时会引发竞态条件. ...
- SiteMesh基础教程
SiteMesh是由一个基于Web页面布局.装饰以及与现存Web应用整合的框架.它能帮助我们在由大量页面构成的项目中创建一致的页面布局和外观,如一致的导航条,一致的banner,一致的版权,等等. 教 ...
- java String长度与varchar长度匹配理解(字符和字节长度理解)
java String长度与varchar长度匹配理解(字符和字节长度理解) string中的length()长度,返回的是char的数量,每个char可以存储世界上任何类型的文字和字符,一个char ...
- 阿里云nginx创建多站点
最近开始用阿里云的vps,用了它的一键安装包安装了php环境,nginx的.下面记录创建多站点的心得. 首先php安装好后会自带安装一个phpwind的站点. 文件目录存放在 /alidata/www ...
- golang 的GOPATH设置的问题
go run footer.go 的时候呢, go会依次去GOPATH 和GOROOT设置的对应路径下面找对应的包(目录和文件) 找的时候呢, 会在GoPATH 和GOROOT对应的目录后面再加一层路 ...
- Android:Unable to resolve target ‘android-8’问题解决
在学习过程中,下载别人写过的代码,导入到eclipse,报错: Unable to resolve target 'android-8' 问题是项目版本号问题. 解决方法例如以下: 右击项目:Prop ...
- Shiro学习(22)集成验证码
在做用户登录功能时,非常多时候都须要验证码支持,验证码的目的是为了防止机器人模拟真有用户登录而恶意訪问,如暴力破解用户password/恶意评论等. 眼下也有一些验证码比較简单,通过一些OCR工具就能 ...
- 【EasyUi DataGrid】批量删除
DataGrid是我们做网页经常使用到的组件之中的一个,对它的操作也无非是增删改查操作.单条数据的增删改相对来说比較简单.添加.改动能够直接在DataGrid中进行,也能够用弹出框的形式把数据装载在文 ...