javadoc 中已经说明了一切,我引用:
与直接注入 T 相比 (仅隐式使用 @Inject),注入 Provider<T> 可以:
- 检索多个实例。
- 实例的延迟或可选检索。
- 打破循环依赖关系。
- 抽象范围,以便您可以从包含范围内的实例中查找较小范围内的实例。
#1 的示例:
在这里,您从同一个提供者那里获得了多个Seat 实例,因此它被用作工厂。
class Car {
@Inject
Car(Provider<Seat> seatProvider) {
Seat driver = seatProvider.get();
Seat passenger = seatProvider.get();
...
}
}
#2 的示例:
这里您使用提供程序来避免直接创建类MyClassLongToCreate 的实例,因为我们知道这是一个缓慢的操作,因此我们将通过get 方法仅在需要时才懒惰地获取它。
class MyClass {
@Inject
private Provider<MyClassLongToCreate> lazy;
...
}
#3 的示例:
这是一个循环依赖,容器无法轻易解决,因此某些容器可能会抛出异常,因为它们不知道如何自己解决。
class C1 {
private final C2 c2;
@Inject
C1(C2 c2) {
this.c2 = c2;
...
}
}
class C2 {
private final C1 c1;
@Inject
C2(C1 c1) {
this.c1 = c1;
...
}
}
为了解决这个问题,我们在至少一个构造函数上使用Provider 来打破循环依赖:
class C1 {
private final Provider<C2> c2;
@Inject
C1(Provider<C2> c2) {
this.c2 = c2;
...
}
}
这将允许容器首先完全创建C1 的实例(因为我们实际上不需要创建C2 的实例来注入C2 的提供者)一旦完成,容器将能够从C1 的实例创建C2 的实例。
#4 示例:
这里有一个类C2,它的作用域是会话,它依赖于C1,它的作用域是请求,我们使用提供程序来允许我们获取与当前请求对应的C1 的实例因为它会从一个请求更改为另一个请求。
@RequestScoped
public class C1 {
...
}
@SessionScoped
public class C2 {
@Inject
private Provider<C1> provider;
...
public void doSomething() {
// Get the instance corresponding to the current request
C1 c1 = provider.get();
...
}
}