0

我有一个对外部供应商进行 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 实例?

如果两者都是肯定的,那么注入配置会不必要地创建新实例,这不是一个好主意。

4

2 回答 2

4

默认情况下,Guice 总是创建一个新实例。除非您通过例如将对象注释为@singleton或配置Provider使用某些缓存或使用bind显式指向在需要某些类时应使用的实例来将其配置为重用实例。

这是一个理想的行为,因为有很多与使用单例相关的问题和错误(例如,使用单例更容易产生内存泄漏),所以这必须是程序员有意识的、明确的决定,他们应该确保它不会咬他们。

于 2020-05-08T10:05:03.690 回答
0

Play 中的路由器是单例的

@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
于 2020-05-08T12:29:08.127 回答