Guice 中作用域注解和作用域实例的区别
The difference between a scoping annotation and scope instances in Guice
在 Guice 中,当您指示某个实例的生命周期时,您将使用像 bind(Applebees.class).in(Singleton.class);
这样的作用域注释。
或者您似乎可以使用
之类的范围实例
bind(UserPreferences.class)
.toProvider(UserPreferencesProvider.class)
.in(ServletScopes.REQUEST);
并且 Guice 官方推荐前一种方法,因为前一种方法允许我们重用模块 class。
但我不确定这一点。我的假设是这样的,所以请检查是否正确。
Scope instances是Servelet的术语,所以如果你采用scope instances而不是scoping annotations,Module class只适用于Servelet。另一方面,如果您使用作用域注释,则可以重用您的模块 class 除非您放弃 Guice。
那么,这样对吗?你能查一下吗?
我相信你的理解是正确的,但对于什么样的重用会受到影响,有一点微妙之处。
您可能指的是 the Guice wiki on Scopes 中的这段文字(强调我的):
The in()
clause accepts either a scoping annotation like RequestScoped.class
and also Scope
instances like ServletScopes.REQUEST
:
bind(UserPreferences.class)
.toProvider(UserPreferencesProvider.class)
.in(ServletScopes.REQUEST);
The annotation is preferred because it allows the module to be reused in different types of applications. For example, an @RequestScoped
object could be scoped to the HTTP request in a web app and to the RPC when it's in an API server.
即使使用 Guice 的 servlet-specific 作用域,您也可以在作用域实例 ServletScopes.REQUEST and the @RequestScoped annotation, and choose between in(Scope scope)
and in(Class scopeAnnotation)
accordingly (see ScopedBindingBuilder 之间进行选择。几乎每个范围都应该有一个相应的注释,因为它们在 类 和 @Provides 方法上特别有用。
重要的是要意识到这里总是一个Scope instance that actually implements the scoping behavior (specifically, wrapping an unscoped Provider so that it can return already-returned instances in the right conditions). To associate an annotation to a Scope instance, you need to make sure that a module calls bindScope
, which accepts the Scope annotation class and the Scope instance; for Servlets, Guice has this binding automatically installed via InternalServletModule。
@Override
protected void configure() {
bindScope(RequestScoped.class, REQUEST);
bindScope(SessionScoped.class, SESSION);
// ...
}
那么使用 in(Class scopeAnnotation)
有什么好处? 当绑定到一个 Scope 实例时,您是在告诉 Guice 您想要使用哪个 Scope 实例,而不是允许用户有机会使用 bindScope
将注释绑定到不同的 Scope 实例。在我上面加粗的示例中,您可以想象使用相同的模块而不使用实际的 Guice servlet 扩展(注解除外),但是 只有绑定到注解 类 和然后自己打电话 bindScope
。如果您使用 in(Scope)
进行绑定,则需要更改该行或编写一个新模块。
这对于您自己的自定义范围实例和注释尤其重要,因为它允许您在整个应用程序中一致地更改范围行为:
@Override public void configure() {
// BAD: To change the scope, you'll need to change three lines.
// If you don't change all three together, you'll get inconsistent behavior.
bind(A.class).to(AImpl.class).in(MyScope.INSTANCE);
bind(B.class).to(BImpl.class).in(MyScope.INSTANCE);
bindScope(AScoped.class, MyScope.INSTANCE);
}
@Override public void configure() {
// GOOD: To change the scope, you can change one line, and optionally
// extract that line to a separate Module.
bind(A.class).to(AImpl.class).in(AScoped.class);
bind(B.class).to(BImpl.class).in(AScoped.class);
bindScope(AScoped.class, MyScope.INSTANCE);
}
在 Guice 中,当您指示某个实例的生命周期时,您将使用像 bind(Applebees.class).in(Singleton.class);
这样的作用域注释。
或者您似乎可以使用
bind(UserPreferences.class)
.toProvider(UserPreferencesProvider.class)
.in(ServletScopes.REQUEST);
并且 Guice 官方推荐前一种方法,因为前一种方法允许我们重用模块 class。 但我不确定这一点。我的假设是这样的,所以请检查是否正确。
Scope instances是Servelet的术语,所以如果你采用scope instances而不是scoping annotations,Module class只适用于Servelet。另一方面,如果您使用作用域注释,则可以重用您的模块 class 除非您放弃 Guice。
那么,这样对吗?你能查一下吗?
我相信你的理解是正确的,但对于什么样的重用会受到影响,有一点微妙之处。
您可能指的是 the Guice wiki on Scopes 中的这段文字(强调我的):
The
in()
clause accepts either a scoping annotation likeRequestScoped.class
and alsoScope
instances likeServletScopes.REQUEST
:bind(UserPreferences.class) .toProvider(UserPreferencesProvider.class) .in(ServletScopes.REQUEST);
The annotation is preferred because it allows the module to be reused in different types of applications. For example, an
@RequestScoped
object could be scoped to the HTTP request in a web app and to the RPC when it's in an API server.
即使使用 Guice 的 servlet-specific 作用域,您也可以在作用域实例 ServletScopes.REQUEST and the @RequestScoped annotation, and choose between in(Scope scope)
and in(Class scopeAnnotation)
accordingly (see ScopedBindingBuilder 之间进行选择。几乎每个范围都应该有一个相应的注释,因为它们在 类 和 @Provides 方法上特别有用。
重要的是要意识到这里总是一个Scope instance that actually implements the scoping behavior (specifically, wrapping an unscoped Provider so that it can return already-returned instances in the right conditions). To associate an annotation to a Scope instance, you need to make sure that a module calls bindScope
, which accepts the Scope annotation class and the Scope instance; for Servlets, Guice has this binding automatically installed via InternalServletModule。
@Override
protected void configure() {
bindScope(RequestScoped.class, REQUEST);
bindScope(SessionScoped.class, SESSION);
// ...
}
那么使用 in(Class scopeAnnotation)
有什么好处? 当绑定到一个 Scope 实例时,您是在告诉 Guice 您想要使用哪个 Scope 实例,而不是允许用户有机会使用 bindScope
将注释绑定到不同的 Scope 实例。在我上面加粗的示例中,您可以想象使用相同的模块而不使用实际的 Guice servlet 扩展(注解除外),但是 只有绑定到注解 类 和然后自己打电话 bindScope
。如果您使用 in(Scope)
进行绑定,则需要更改该行或编写一个新模块。
这对于您自己的自定义范围实例和注释尤其重要,因为它允许您在整个应用程序中一致地更改范围行为:
@Override public void configure() {
// BAD: To change the scope, you'll need to change three lines.
// If you don't change all three together, you'll get inconsistent behavior.
bind(A.class).to(AImpl.class).in(MyScope.INSTANCE);
bind(B.class).to(BImpl.class).in(MyScope.INSTANCE);
bindScope(AScoped.class, MyScope.INSTANCE);
}
@Override public void configure() {
// GOOD: To change the scope, you can change one line, and optionally
// extract that line to a separate Module.
bind(A.class).to(AImpl.class).in(AScoped.class);
bind(B.class).to(BImpl.class).in(AScoped.class);
bindScope(AScoped.class, MyScope.INSTANCE);
}