В чем разница между Inject и Provider в JSR-330
Все
Я не знаю, в чем разница между Inject и Provider в JSR-330. Я использую Google Guice, и каждый день использую @Inject
и я знаю в JSR-330, он имеет Provider<T>
,
Мой вопрос
- что значит
Provider<T>
? - когда может когда пользователь
Provider<T>
? - какая разница с
@Inject
?
Заранее спасибо.
1 ответ
Все уже объяснено в 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
), когда контейнер будет готов, он сможет создать экземпляр C2
из этого экземпляра C1
,
Пример для № 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();
...
}
}