一直以来都对Akka中的actor创建过程有点迷糊,说是知道但是又有所不清楚,这次有空把源码翻了一下,顺便记录下自己的理解,有错误的地方还请指正
大家应该都知道一般我们要创建actor都要去调用context.actorOf方法或者actorSystem.actorOf这两种方法,其中actorSystem创建的actor会直接挂在user路径下,也是用户可以创建的最高层次的actor节点。通过观察源码发现,actorContext和actorSystem都继承了ActorRefFactory,这里是真正发起actorOf方法的所在地
abstract class ActorSystem extends ActorRefFactory{...}
trait ActorContext extends ActorRefFactory{...} //ActorContext 就是我们在actor中可以直接调用的context对象
先看一下actorOf的方法定义
def actorOf(system: ActorSystemImpl, props: Props, supervisor: InternalActorRef,
path: ActorPath,systemService: Boolean, deploy: Option[Deploy],
lookupDeploy: Boolean, async: Boolean): InternalActorRef
几个参数含义大概如下
case NoRouter ⇒ blabla…
case router ⇒blabla…
进入方法有2个case条件,一个是NoRouter一个是router,顾名思义,不再解释太多,下面重点看下NoRouter的情况。
首先是解析deploy,用deploy中定义的mailbox和dispatcher去覆盖props中的值
val props2 =
// mailbox and dispatcher defined in deploy should override props
(if (lookupDeploy) deployer.lookup(path) else deploy) match {
case Some(d) ⇒
(d.dispatcher, d.mailbox) match {
case (Deploy.NoDispatcherGiven, Deploy.NoMailboxGiven) ⇒ props
case (dsp, Deploy.NoMailboxGiven) ⇒ props.withDispatcher(dsp)
case (Deploy.NoMailboxGiven, mbx) ⇒ props.withMailbox(mbx)
case (dsp, mbx) ⇒ props.withDispatcher(dsp).withMailbox(mbx)
}
case _ ⇒ props // no deployment config found
}
val dispatcher = system.dispatchers.lookup(props2.dispatcher)
val mailboxType = system.mailboxes.getMailboxType(props2, dispatcher.configurator.config)
if (async)
new RepointableActorRef(system, props2, dispatcher, mailboxType, supervisor, path)
.initialize(async)
else
new LocalActorRef(system, props2, dispatcher, mailboxType, supervisor, path)
这里的dispatchers其实是我们配置中定义的那些dispatcher配置,不难猜到就是解析配置文件再使用反射去创建对应的dispatcher,可以简单参阅一下创建代码,分别解析dispatcher的type去创建不同类型的dispatcher
cfg.getString("type") match {
case "Dispatcher" ⇒ new DispatcherConfigurator(cfg, prerequisites)
case "BalancingDispatcher" ⇒
throw new IllegalArgumentException("BalancingDispatcher is deprecated, use a BalancingPool instead. " +
"During a migration period you can still use BalancingDispatcher by specifying the full class name: " +
classOf[BalancingDispatcherConfigurator].getName)
case "PinnedDispatcher" ⇒ new PinnedDispatcherConfigurator(cfg, prerequisites)
case fqn ⇒
val args = List(classOf[Config] → cfg, classOf[DispatcherPrerequisites] → prerequisites)
prerequisites.dynamicAccess.createInstanceFor[MessageDispatcherConfigurator](fqn, args).recover({
case exception ⇒
throw new ConfigurationException(
("Cannot instantiate MessageDispatcherConfigurator type [%s], defined in [%s], " +
"make sure it has constructor with [com.typesafe.config.Config] and " +
"[akka.dispatch.DispatcherPrerequisites] parameters")
.format(fqn, cfg.getString("id")), exception)
}).get
}
这里的mailboxType名字比较令人费解,点进去才知道原来是一个创建MessageQueue的工厂类,同样这里也是根据一些配置去加载不同的MessageQueue实现
- MailboxType is a factory to create MessageQueues for an optionally
private val actorCell: ActorCell = newActorCell(_system, this, _props, _dispatcher, _supervisor)
actorCell.init(sendSupervise = true, _mailboxType)
-在actorCell中才会真正创建邮箱并将actor绑定到他上面,并且在初始化之后会发送一些对应的系统信息
RepointableActorRef 的创建有所不同,因为是异步的,所以这里有调用到了Unsafe类去异步创建cell,并且他里面会有一个underlying和一个lookup的cell,具体原因可以参考如下的官方注释,笔者现在理解还不是很透彻不敢贸然解释
/*
* There are two main functions of a Cell: message queueing and child lookup.
* When switching out the UnstartedCell for its real replacement, the former
* must be switched after all messages have been drained from the temporary
* queue into the real mailbox, while the latter must be switched before
* processing the very first message (i.e. before Cell.start()). Hence there
* are two refs here, one for each function, and they are switched just so.
*/
def underlying: Cell = Unsafe.instance.getObjectVolatile(this, cellOffset).asInstanceOf[Cell]
def lookup = Unsafe.instance.getObjectVolatile(this, lookupOffset).asInstanceOf[Cell]