Scala 实现映射条目侦听器
我正在尝试用Scala实现映射条目侦听器 想法:Scala 实现映射条目侦听器,scala,akka,listener,Scala,Akka,Listener,我正在尝试用Scala实现映射条目侦听器 想法: 我需要从服务订阅地图 当添加/更新带有特定密钥的条目时,我需要通知地图的所有订阅者 我需要从其他服务访问地图以检查输入值 我找不到现成的解决方案,所以我尝试用Akka实现它: class TrackingService(system: ActorSystem) extends LazyLogging { private val trackingActor = system.actorOf(TrackingActor.props) priv
class TrackingService(system: ActorSystem) extends LazyLogging {
private val trackingActor = system.actorOf(TrackingActor.props)
private val duration = Duration(15, TimeUnit.SECONDS)
private implicit val timeout = Timeout(duration)
def fireEvent(key: String): Unit = {
TrackingActor ! EventFired(key)
}
def eventHappened(key: String): Future[Boolean] = {
TrackingActor ? DoesEventHappened(key)).mapTo[Boolean]
}
def registerHiddenCardListener(key: String, data: MyData): Unit = {
TrackingActor ! Subscribe(key, data)
}
}
case class EventFired(key: String)
case class EventHappened(key: String)
case class EventHappenedResponse(happened: Boolean)
case class Subscribe(key: String, data: Data)
class TrackingActor extends Actor with LazyLogging {
var eventMap: Map[String, Boolean] = Map.empty[String, Boolean]
var dataMap: Map[String, List[Data]] = Map.empty[String, List[Data]]
def receive: Receive = {
case Subscribe(key, data) =>
val currentData: List[Data] = dataMap.getOrElse(key, Nil)
val newData = data :: currentData
dataMap = dataMap + (key -> newData)
case EventHappened(key) => sender() ! EventHappenedResponse(eventMap.getOrElse(key, false))
case e@EventFired(key) =>
eventMap = eventMap + (key -> true)
for {
dataOpt <- dataMap.get(key)
data <- dataOpt
} {
// do callback with data (e.g. send email)
}
case x => logger.warn(s"Received unknown message: $x")
}
}
object TrackingActor {
def props: Props = Props(classOf[TrackingActor])
}
class TrackingService(系统:ActorSystem)扩展了懒散日志记录{
private val trackingActor=system.actorOf(trackingActor.props)
专用val持续时间=持续时间(15,时间单位。秒)
私有隐式val超时=超时(持续时间)
def fireEvent(键:字符串):单位={
TrackingActor!已触发事件(键)
}
def EventOccessed(键:字符串):未来[布尔]={
TrackingActor?Doeseventhappen(键)).mapTo[布尔值]
}
def registerHiddenCardListener(键:字符串,数据:MyData):单位={
TrackingActor!订阅(密钥、数据)
}
}
案例类EventFired(键:String)
案例类事件已发生(关键字:字符串)
案例类EventHappendResponse(发生:布尔值)
案例类订阅(键:字符串,数据:数据)
类TrackingActor使用LazyLogging扩展了Actor{
var eventMap:Map[String,Boolean]=Map.empty[String,Boolean]
var dataMap:Map[String,List[Data]=Map.empty[String,List[Data]]
def接收:接收={
案例订阅(密钥、数据)=>
val currentData:List[Data]=dataMap.getOrElse(key,Nil)
val newData=data::currentData
dataMap=dataMap+(键->新建数据)
case eventhapped(key)=>sender()!eventhappendresponse(eventMap.getOrElse(key,false))
案例e@EventFired(键)=>
eventMap=eventMap+(键->真)
为了{
dataOpt这里有一个想法:
case class Subscribe[A, B](f: (A, B, NotifyingMap[A,B]) => Any)
case class Event[A, B](key: A, value: B, originator: NotifyingMap[A,B])
case class RegisterObserver(actorRef: ActorRef)
/**
* Subscribes to events
*/
class Subscriber[A,B]{
def register(actorSystem: ActorSystem) = {
val actor = actorSystem.actorOf(Props(classOf[Observer[A,B]]))
actor ! Subscribe(handleEvent)
}
def handleEvent(key: A, value: B, notifyingMap: NotifyingMap[A, B]) = {
println(s"Saw key $key with value $value")
}
}
/**
* Observer of events that will call a partial function when
* an event comes in.
*/
class Observer[A, B] extends Actor{
var f: (A,B,NotifyingMap[A,B]) => Any = _
def receive = {
case x: Subscribe[A, B] =>
f = x.f
Notifier() ! RegisterObserver(self)
case e: Event[A,B] =>
f(e.key, e.value, e.originator)
}
}
/**
* Notifier that sends out the event to all registered observers.
*/
class Notifier extends Actor {
var observers = List[ActorRef]()
def receive = {
case x: RegisterObserver =>
observers = x.actorRef :: observers
case x: Event[_,_] =>
observers.foreach(_ ! Event)
}
}
/**
* Singleton notifier.
*/
object Notifier{
var notifier: ActorRef = _
def create(actorSystem: ActorSystem) =
actorSystem.actorOf(Props(classOf[Notifier]))
def apply(): ActorRef = notifier
}
/**
* Class that sends out an event when an item is put. Also allows for
* getting an item based on a key.
*/
class NotifyingMap[A, B](){
val map: TrieMap[A,B] = TrieMap[A,B]()
// Specific business logic here on when you publish the event.
def put(key: A, value: B) = {
map.put(key, value).foreach(v => Notifier() ! Event(key, v, this))
}
def get(key: A) = map.get(key)
}
通过这样做,您可以使订阅者成为一个非参与者
类,同时仍然允许它对事件做出反应。您还可以在通知映射
上调用普通的旧方法,因为它只是一个类而不是参与者
我个人喜欢在消息中存储回调信息。通常情况下,您可以通过在case类中使用另一个ActorRef
来看到这一点。在本例中,我们在case类中使用了NotifyingMap
,因此我们知道事件的起源,并可以在那里适当地调用get
方法
完全公开:我没有运行任何代码。它可以编译