1.Play框架依赖注入介绍
Play框架提供基于JSR 330的依赖注入。Play默认的JSR 330的实现是用Guice实现的,但是其它的JSR 330实现也可以用。
2.声明依赖
如果你有个组件(例如Controller)需要依赖其它组件,那么你就可以通过使用@Inject注解来声明。@Inject注解可以在属性或者构造方法上使用。例如,注入一个属性:
import javax.inject.*;
import play.libs.ws.*;
public class MyComponent {
@Inject WSClient ws;
// ...
}
注意这些是实例变量,通常情况下注入一个静态属性是没有意义的,因为它会失去封装的意义。
另一个例子,注入一个构造方法:
import javax.inject.*;
import play.libs.ws.*;
public class MyComponent {
private final WSClient ws;
@Inject
public MyComponent(WSClient ws) {
this.ws = ws;
}
// ...
}
虽然属性注入更短,但比较推荐使用构造方法注入的方式。这样更可测试,由于在单元测试中你需要传入所有的构造方法参数来创建一个对象实例,编译器需要确保依赖存在。且由于没有setter的存在,构造方法注入的方式也更易于理解。
3.组件的生命周期
依赖注入系统管理注入组件的生命周期,当需要时创建它们然后将其注入到其它组件中。以下是组件生命周期如何工作的介绍:
- 在任何时候,当某个组件被需要时就被创建。如果一个组件不止一次的被用到,默认情况下,将会创建多个组件实例。如果你只想创建一个该组件的单例,你需要用@Singleton注解将其标记为一个单例。
- 实例在它们被需要时会懒加载。如果一个组件从来都未被其它组件使用,那么它根本不会被创建。这通常情况下是有意义的,但是在一些情况下,你希望组件被立即加载哪怕它们从未被使用。举例来说,你可能要向一个远端系统发送一个信息或者在系统启动时预加载一个缓存。你可以通过使用eager binding的方式强制创建一个组件。
- 实例不会被自动清理,除了正常的垃圾回收。当组件不再被引用时,将会被GC回收,但是Play框架不会做任何特殊的事情来关闭组件,例如close方法。无论如何,Play提供了一类叫做closeApplicationLifecycly的特殊的组件,你可以将其注册进去以在系统停止的时候关闭它们。
4.单例
有时你或许想让组件保持一些状态,例如缓存或者一个连向外部资源的链接,或者一个创建成本很高的组件。在这些情况下,创建一个该组件的单例是非常重要的。这些需求可以通过使用@Singleton注解来实现。例如:
import javax.inject.*;
@Singleton
public class CurrentSharePrice {
private volatile int price;
public void set(int p) {
price = p;
}
public int get() {
return price;
}
}
5.停止/清理
当Play框架关闭时,一些组件需要被清理,例如停止线程池。Play框架提供了ApplicationLifecycle组件来注册这些需要在Play关闭时清理的组件:import javax.inject.*;
import play.inject