AI智能
改变未来

Google Guice之作用域

默认情况下,Guice获取一个实例时,每次都会返回一个新的对象。这个行为可以通过scopes进行配置。Scopes允许你复用实例:应用整个生命周期(

@Singleton

),会话(

@Session

),请求(

@RequestScoped

),Guice还提供为Web应用提供了一种

Servlet

扩展作用域。并且在Guice还可以自定义范围。

Guice使用注解来标识作用域,将注解添加到某一类型的实现类上:

@Singletonpublic class InMemoryTransactionLog implements TransactionLog {/* everything here should be threadsafe! */}

作用域也可以使用

bind

语句进行配置:

bind(TransactionLog.class).to(InMemoryTransactionLog.class).in(Singleton.class);

@Provides

方法添加作用域注解:

@Provides @SingletonTransactionLog provideTransactionLog() {...}

如果在配置作用域时,使用注解与

bind()

语句存在冲突,那么以

bind()

中的配置为准。如果某一类型不想指定作用域则可以使用

Scopes.NO_SCOPE

在链接绑定中,作用域是应用于绑定源上,而不是应用了绑定目标上。假如我们有一个

Appleess

类实现了

Bar

Grill

接口,下面的绑定配置就存在两个实例,一个用于

Bar

,另一个用于

Grill

bind(Bar.class).to(Applebees.class).in(Singleton.class);bind(Grill.class).to(Applebees.class).in(Singleton.class);

这是因为作用域应用于绑定源(

Bar

Grill

),而不是绑定目标(

Appless

),如果要求只创建一个实例,则可以在

Appless

类上添加

@Singleton

注解,或者再添加一个绑定配置:

bind(Applebees.class).in(Singleton.class);

该绑定配置就使得两个

.in(Singleton.class)

语句变得多余了。

in()

语句不仅可以接收一个Scope注解,如

RequestScope.class

,还可以接收Scope实例,如

ServletScopes.REQUEST

:

bind(UserPreferences.class).toProvider(UserPreferencesProvider.class).in(ServletScopes.REQUEST);

使用注解来配置作用域更加合适,因为这样复用

Module

对象。

Guice有一种特殊的语法来定义需要立即创建的单例对象(Eager Singletons):

bind(TransactionLog.class).to(InMemoryTransactionLog.class).asEagerSingleton();

Eager Singletons对象保证终端使用者获得始终如一的体验,Lazy singletons则更适用于edit-compile-run开发周期。可以通过Stage枚举来选择使用哪一种策略。

PRODUCTION DEVELOPMENT
.asEagerSingleton() eager eager
.in(Singleton.class) eager lazy
.in(Scopes.SINGLETON) eager lazy
@Singleton eager* lazy

*

号表示只有已知类型才会立即创建单例对象,所谓已知类型为在

Module

中使用的类加上这些类的传递性依赖。

如何选择作用域:

如果一个对象是有状态的,则每个应用使用则是

@Singleton

,每个请求使用则是

@RequestScoped

。如果一个对象是无状态的并且创建的代价很小,就没有必要配置作用域了,Guice每次都创建一个新的对象。

单例模式在Java应用中很流行,但这样不能提供多个对象特别是在使用了依赖注入之后。虽然单例模式减少了对象的创建、使垃圾回收推后,但单例对象的初始化需要进行同步。单例对象最适用于:

  1. 有状态对象,如果配置对象或者计数器
  2. 要花很大的代价去创建或者查找
  3. 捆绑了资源的对象,例如数据库连接池

当一个类加上了

@Singleton

或者

@SessionScoped

注解时,它必须是线程安全的。而且被注入到这个类中的类也必须是安全的,应该限制需要进行并发控制状态以最大限度地减少可变性。

@RequestScoped

对象不一定是线程安全的,所以一个常见的错误是一个

@Singleton

@SessionScoped

对象依赖了一个

@RequestScoped

对象。
——————————– END ——————————-

及时获取更多精彩文章,请关注公众号《Java精讲》。

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » Google Guice之作用域