Spark定义了一个特质[1]ListenerBus,可以接收事件并且将事件提交到对应事件的监听器。为了对ListenerBus有个直观的理解,我们先来看看它的代码实现,见代码清单1。
代码清单1 ListenerBus的定义
private[spark] trait ListenerBus[L <: AnyRef, E] extends Logging {
private[spark] val listeners = new CopyOnWriteArrayList[L]
final def addListener(listener: L): Unit = {
listeners.add(listener)
}
final def removeListener(listener: L): Unit = {
listeners.remove(listener)
}
final def postToAll(event: E): Unit = {
val iter = listeners.iterator
while (iter.hasNext) {
val listener = iter.next()
try {
doPostEvent(listener, event)
} catch {
case NonFatal(e) =>
logError(s"Listener ${Utils.getFormattedClassName(listener)} threw an exception", e)
}
}
}
protected def doPostEvent(listener: L, event: E): Unit
private[spark] def findListenersByClass[T <: L : ClassTag](): Seq[T] = {
val c = implicitly[ClassTag[T]].runtimeClass
listeners.asScala.filter(_.getClass == c).map(_.asInstanceOf[T]).toSeq
}
}
代码清单1中展示了ListenerBus是个泛型特质,其泛型参数为 [L <: AnyRef, E],其中L是代表监听器的泛型参数,可以看到ListenerBus支持任何类型的监听器,E是代表事件的泛型参数。ListenerBus中各个成员的作用如下:
- listeners:用于维护所有注册的监听器,其数据结构为CopyOnWriteArrayList[L];
- addListener:向listeners中添加监听器的方法,由于listeners采用CopyOnWriteArrayList来实现,所以addListener方法是线程安全的;
- removeListener:从listeners中移除监听器的方法,由于listeners采用CopyOnWriteArrayList来实现,所以removeListener方法是线程安全的;
- postToAll:此方法的作用是将事件投递给所有的监听器。虽然CopyOnWriteArrayList本身是线程的安全的,但是由于postToAll方法内部引入了“先检查后执行”的逻辑,因而postToAll方法不是线程安全的,所以所有对postToAll方法的调用应当保证在同一个线程中;
- doPostEvent:用于将事件投递给指定的监听器,此方法只提供了接口定义,具体实现需要子类提供;
- findListenersByClass:查找与指定类型相同的监听器列表。
今后,将对以下内容分别开辟博文进行介绍:
[1] 特质是Scala语言中提供真正的多重继承的语法特性,类似于Java的Interface,但是又可以实现方法。有关Scala特质的更多介绍请访问Scala官网http://www.scala-lang.org。
关于《Spark内核设计的艺术 架构设计与实现》
经过近一年的准备,《Spark内核设计的艺术 架构设计与实现》一书现已出版发行,图书如图:
纸质版售卖链接如下:
京东:https://item.jd.com/12302500.html