Scala 实现映射条目侦听器

Scala 实现映射条目侦听器,scala,akka,listener,Scala,Akka,Listener,我正在尝试用Scala实现映射条目侦听器 想法: 我需要从服务订阅地图 当添加/更新带有特定密钥的条目时,我需要通知地图的所有订阅者 我需要从其他服务访问地图以检查输入值 我找不到现成的解决方案,所以我尝试用Akka实现它: class TrackingService(system: ActorSystem) extends LazyLogging { private val trackingActor = system.actorOf(TrackingActor.props) priv

我正在尝试用Scala实现映射条目侦听器

想法:

  • 我需要从服务订阅地图
  • 当添加/更新带有特定密钥的条目时,我需要通知地图的所有订阅者
  • 我需要从其他服务访问地图以检查输入值
  • 我找不到现成的解决方案,所以我尝试用Akka实现它:

    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
    方法

    完全公开:我没有运行任何代码。它可以编译