Guice DI是否每次都创建一个新的WSClient实例
Does Guice DI create a new WSClient instance everytime
我有一个客户端 class 向外部供应商发出 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如下所示
class MyClient @Inject()(ws: WSClient, appConfig: Configuration)
(implicit ec: ExecutionContext) {...}
我想了解两件事
- 注入器是否为每个请求注入一个新的 MyClient 实例?
- 如果是,注入器是否每次都注入一个新的 WSClient 和 Configuration 实例?
如果两者都是肯定的,那么注入配置会不必要地创建新实例,这不是一个好主意。
默认情况下,Guice 总是创建一个新实例。除非您将其配置为通过例如重用实例将对象注释为 @singleton
或配置使用某些缓存的 Provider
或使用 bind
明确指向在需要某些 class 时应使用的实例..
这是一种理想的行为,因为存在许多与使用单例相关的问题和错误(例如,使用它们更容易产生内存泄漏),因此这必须是程序员有意识的、明确的决定,谁应该确保它不会咬到他们。
Play 中的路由器是 singleton
@Singleton
class RoutesProvider @Inject() (
injector: Injector,
environment: Environment,
configuration: Configuration,
httpConfig: HttpConfiguration
) extends Provider[Router] {
...
bind[Router].toProvider[RoutesProvider]
这实际上意味着即使控制器 class 没有用 @Singleton
注释,注入的控制器实例在请求之间是 ,除非路由以 @
运算符为前缀在 routes
:
...if you prefix a controller with @ ... a new action instantiated per
request.
例如,给定
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
不同的请求总是return相同的身份,尽管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
我有一个客户端 class 向外部供应商发出 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如下所示
class MyClient @Inject()(ws: WSClient, appConfig: Configuration)
(implicit ec: ExecutionContext) {...}
我想了解两件事
- 注入器是否为每个请求注入一个新的 MyClient 实例?
- 如果是,注入器是否每次都注入一个新的 WSClient 和 Configuration 实例?
如果两者都是肯定的,那么注入配置会不必要地创建新实例,这不是一个好主意。
默认情况下,Guice 总是创建一个新实例。除非您将其配置为通过例如重用实例将对象注释为 @singleton
或配置使用某些缓存的 Provider
或使用 bind
明确指向在需要某些 class 时应使用的实例..
这是一种理想的行为,因为存在许多与使用单例相关的问题和错误(例如,使用它们更容易产生内存泄漏),因此这必须是程序员有意识的、明确的决定,谁应该确保它不会咬到他们。
Play 中的路由器是 singleton
@Singleton
class RoutesProvider @Inject() (
injector: Injector,
environment: Environment,
configuration: Configuration,
httpConfig: HttpConfiguration
) extends Provider[Router] {
...
bind[Router].toProvider[RoutesProvider]
这实际上意味着即使控制器 class 没有用 @Singleton
注释,注入的控制器实例在请求之间是 @
运算符为前缀在 routes
:
...if you prefix a controller with @ ... a new action instantiated per request.
例如,给定
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
不同的请求总是return相同的身份,尽管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