Настройка поведения актера с помощью typesafe Config и HOCON

Я создаю большую агентную/многоагентную модель фондовой биржи, используя Akka/Play/Scala и т. д., и я немного пытаюсь понять, как настроить мое приложение. Ниже приведен фрагмент кода, который иллюстрирует пример проблемы, с которой я сталкиваюсь:

class Exchange extends Actor {

  val orderRoutingLogic = new OrderRoutingLogic()

  val router = {

    val marketsForSecurities = securities.foreach { security =>

      val marketForSecurity = context.actorOf(Props[DoubleAuctionMarket](
        new DoubleAuctionMarket(security) with BasicMatchingEngine), security.name
      )
      orderRoutingLogic.addMarket(security, marketForSecurity)

    }
    Router(orderRoutingLogic)

  }

В приведенном выше фрагменте я вставляю BasicMatchingEngine в DoubleAuctionMarket. Однако я написал несколько различных механизмов сопоставления и хотел бы иметь возможность настроить тип механизма сопоставления, введенный в DoubleAuctionMarket в файле конфигурации приложения.

Можно ли настроить этот уровень приложения с помощью файлов конфигурации typesafe Config и HOCON?


person davidrpugh    schedule 30.12.2014    source источник


Ответы (1)


интересный случай. Если я вас правильно понял, вы хотите настроить смешивание Market актеров с каким-то MatchingEngine типом, указанным в конфиге?

Некоторое уточнение: вы не можете просто смешивать динамический тип. Я имею в виду, если вы переместите тип MatchingEngine в конфиг - он будет известен только во время выполнения, когда конфиг будет парситься. И в это время вы не сможете создать экземпляр new DoubleAuctionMarket(security) with ???SomeClassInstance???. Но, может быть, вы могли бы заменить наследование агрегацией. Может быть, экземпляр MatchingEngine можно передать в Market как параметр?

Теперь, как получить экземпляр MatchingEngine из конфига? Короче говоря, в Typesafe Config нет парсера для FQCN свойства, но это несложно сделать самостоятельно с помощью отражения. Эта техника используется во многих местах Акки. Сначала посмотрите здесь . Свойство provider задается как строка fqcn и может быть изменено на другого поставщика (например, RemoteActorRefProvider) в других конфигурациях. Теперь посмотрите, как он обрабатывается для получения экземпляра Provider. Сначала он просто читается как строка здесь. Затем ProviderClass используется для создания экземпляра фактического (среды выполнения) провайдера здесь. DynamicAccess — это утилита, помогающая с рефлексивными вызовами. Он недоступен публично через context.system, но просто возьмите его часть или создайте экземпляр самостоятельно, я не думаю, что это большая проблема.

С некоторыми изменениями ваш код может выглядеть так:

class Exchange extends Actor {

  val orderRoutingLogic = new OrderRoutingLogic()
  val matchingEngineClass = context.system.settings.config.getString("stocks.matching-engine")
  val matchingEngine = DynamicAccess.createInstance[MatchingEngine](matchingEngineClass)

  val router = {

    val marketsForSecurities = securities.foreach { security =>

      val marketForSecurity = context.actorOf(DoubleAuctionMarket.props(security, matchingEngine))
      orderRoutingLogic.addMarket(security, marketForSecurity)

    }
    Router(orderRoutingLogic)

  }

Я переместил реквизиты в сопутствующий объект DoubleAuctionMarket, как указано в рекомендуемых правилах акка документы. Использование Props(new Actor()) — опасная практика.

person alkersan    schedule 06.01.2015
comment
Спасибо. Это кажется очень близким к тому, что я хочу сделать. Возможно, мой вопрос несколько некорректен: то, что я хочу, может относиться к тому, как управлять внедрением зависимостей для большой модели/приложения? Похоже, что есть библиотеки (например, Guice, Spring и Play), которые могут помочь в этом. Ваш ответ также кажется шагом в этом направлении. Я подумаю и вернусь к вам. - person davidrpugh; 07.01.2015