Создает ли Guice DI каждый раз новый экземпляр WSClient? - PullRequest
0 голосов
/ 08 мая 2020

У меня есть класс Client, который обращается к внешнему поставщику через API. В моем контроллере я ввожу клиента следующим образом.

@Singleton
class AdsController @Inject()(client: MyClient)(
  implicit ec: ExecutionContext
) extends InjectedController {

  def index = Action.async(json.parse[ClientRequest])  {
     client.send(request.body).map({
       case s: SuccessResponse => Ok(Json.toJson(s))
       ...
     }) 
  }
}

Класс клиента выглядит следующим образом


class MyClient @Inject()(ws: WSClient, appConfig: Configuration)
(implicit ec: ExecutionContext) {...}

Я хотел понять две вещи

  1. Добавляет ли инжектор новый экземпляр MyClient для каждого запроса?
  2. Если да, вводит ли инжектор каждый раз новый экземпляр WSClient и Configuration?

Если оба ответа да, то ввод конфигурации без необходимости создает новые экземпляры, что не будет хорошей идеей.

Ответы [ 2 ]

4 голосов
/ 08 мая 2020

Guice по умолчанию всегда создает новый экземпляр. Если вы не настроили его для повторного использования экземпляра, например, пометив объект как @singleton или настроив Provider, который использует некоторый кеш, или используя bind, чтобы явно указать на экземпляр, который должен использоваться, когда требуется какой-то класс ..

Это желаемое поведение, так как есть много проблем и ошибок, связанных с использованием синглтонов (например, с ними проще произвести утечку памяти), поэтому это должно быть сознательное, явное решение программиста, который должен принять уверен, что он их не укусит.

0 голосов
/ 08 мая 2020

Маршрутизатор в Play - это singleton

@Singleton
class RoutesProvider @Inject() (
    injector: Injector,
    environment: Environment,
    configuration: Configuration,
    httpConfig: HttpConfiguration
) extends Provider[Router] {

...

bind[Router].toProvider[RoutesProvider]

, что фактически означает, что даже если класс контроллера не аннотирован с помощью @Singleton, внедренный экземпляр контроллера по умолчанию используется повторно. между запросами, если маршрут не имеет префикса с оператором @ в routes:

... если вы префикс контроллера с @ ... новое действие создается для каждого запроса .

Например, для

class MyClient

class HomeController @Inject()(cc: ControllerComponents, client: MyClient) extends AbstractController(cc) {
  def index = Action {
    Ok(s"HomeController identity = ${this.hashCode}\nMyClient identity = ${client.hashCode}")
  }
}

и следующего routes файла

GET     /                           controllers.HomeController.index

разные запросы всегда возвращают одну и ту же идентификацию, несмотря на HomeController не является одноэлементным

// request 1
HomeController identity = 409392943
MyClient identity = 475611387

// request 2
HomeController identity = 409392943
MyClient identity = 475611387

, однако, если мы используем оператор @ в файле маршрутов

GET     /                           @controllers.HomeController.index

, мы видим, что идентичность меняется при каждом новом запросе:

// request 1
HomeController identity = 1249276649
MyClient identity = 1152488919

// request 2
HomeController identity = 41809453
MyClient identity = 213518354
...