Здесь есть несколько вопросов.
- Каков наилучший способ изменить желаемую реализацию во всем приложении? Посмотрите на
@Alternatives
.
- Нужен ли мне квалификатор для каждой реализации? Нет, см. this ответ на подробное подробное объяснение.
- Должен ли я использовать производителя, чтобы решить, какая реализация была введена? Мог быть решением, которое вы хотите, но я в этом сомневаюсь. Производители обычно используются для выполнения некоторой инициализации, которая не может быть выполнена в конструкторе/
@PostConstruct
. Вы также можете использовать его для проверки точки инъекции и принятия решений о времени выполнения инъекций. См. Ссылку 2. для некоторых подсказок.
Правильное ли решение? Это будет работать, но вам все равно придется возиться с кодом для изменения реализации, поэтому сначала рассмотрите 1.. Также @Calculator Calculator
кажется крайне избыточным. Опять же, см. Ссылку на 2.
@ApplicationScoped
public class CalculatorFctory implements Serializable {
private Calculator calc;
@Produces @Calculator Calculator getCalculator() {
return new Calculator();
}
}
Update:
CDI использует спецификаторы в дополнение к типов для разрешения зависимостей. Другими словами, до тех пор, пока существует только один тип, соответствующий типу точки впрыска, достаточно только типов, и квалификаторы не нужны. Квалификаторы существуют для устранения неоднозначности, когда типов недостаточно.
Например:
public class ImplOne implements MyInterface {
...
}
public class ImplTwo implements MyInterface {
...
}
Чтобы иметь возможность вводить либо реализацию, вам не нужны никакие отборочные:
@Inject ImplOne bean;
или
@Inject ImplTwo bean;
Вот почему я говорю @Calculator Calculator
является избыточным. Если вы определяете квалификатор для каждой реализации, вы не получаете много, можете просто использовать этот тип. Скажем, два отборочные @QualOne
и @QualTwo
:
@Inject @QualOne ImplOne bean;
и
@Inject @QualTwo ImplTwo bean;
Пример непосредственно над ничего не получить, так как в предыдущем примере, не рас-двусмысленности не существовало уже.
Конечно, вы можете сделать это в тех случаях, когда у вас нет доступа к определенным типам реализации:
@Inject @QualOne MyInterface bean; // to inject TypeOne
и
@Inject @QualTwo MyInterface bean; // to inject TypeTwo
Однако ОП не следует использовать @Produces когда он хочет управлять CDI.
@Avinash Singh - CDI управляет @Produces
, а также все, что они вернутся, до тех пор, как это CDI, который вызывает метод. См. this section of the spec, если хотите. Это включает в себя возвращение `@ ... бобы, которые с заданной областью будет поддерживать зависимостей обратных вызовов для инъекций, жизненного цикла и т.д.
я проглядел некоторые детали здесь, так считают следующие два:
public class SomeProducer {
@Inject ImplOne implOne;
@Inject ImplTwo implTwo;
@Inject ImplThree implThree;
@Produces
public MyInterface get() {
if (conditionOne()) {
return implOne;
} else if (conditionTwo()) {
return implTwo;
} else {
return implThree;
}
}
}
и
public class SomeProducer {
@Produces
public MyInterface get() {
if (conditionOne()) {
return new ImplOne();
} else if (conditionTwo()) {
return new ImplTwo();
} else {
return new ImplThree;
}
}
}
Затем, в первом примере, CDI будет управлять жизненным циклом (то есть @PostConstruct
и @Inject
), что возвращается от производителя, но во втором случае это не будет.
Назад к исходному вопросу - что является лучшим способом переключения между реализациями без необходимости изменения источника? Предполагается, что вы хотите, чтобы изменение было широко распространенным.
@Default
public class ImplOne implements MyInterface {
...
}
@Alternative
public class ImplTwo implements MyInterface {
...
}
@Alternative
public class ImplThree implements MyInterface {
...
}
Тогда любое для любого @Inject MyInterface instance
, ImplOne
будет введен, если
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
<alternatives>
<class>ImplTwo</class>
</alternatives>
</beans>
не указан, в этом случае ImplTwo
будет введен повсеместно.
Дальнейшее обновление
Есть действительно вещи в среде Java EE, которые не управляются КДИ, такие как EJBs и веб-сервисов.
Как бы вы ввели веб-сервис в управляемый bean-носитель CDI? Это действительно просто:
@WebServiceRef(lookup="java:app/service/PaymentService")
PaymentService paymentService;
Вот именно, там вы будете иметь действительную ссылку на службу платежей, который управляется за пределами КДИ.
Но, если вы не хотите использовать полный @WebServiceRef(lookup="java:app/service/PaymentService")
везде, где это необходимо? Что делать, если вы хотите только ввести его по типу? Тогда вы делаете это где-то:
@Produces @WebServiceRef(lookup="java:app/service/PaymentService")
PaymentService paymentService;
и в любом КДИ боба, который нуждается в ссылку на эту услугу оплаты вы можете просто @Inject
это с помощью CDI, как это:
@Inject PaymentService paymentService;
Обратите внимание, что перед определением поля производителя , PaymentService
не будет доступен для инъекций CDI способ. Но он всегда доступен по старому пути. Кроме того, в любом случае веб-служба не управляется CDI, но определение поля производителя просто делает ссылку на веб-службу доступной для инъекции способом CDI.
Пожалуйста, смотрите мое обновление в соответствии с вашим комментарием. Кроме того, производители и все, что они возвращают, управляются CDI ... – rdcrng
Нет никакой причины комментировать что-либо с помощью '@ Produces', если вы собираетесь его называть. – rdcrng
Как бы вы применили эту услугу к компоненту CDI? Мы будем использовать '@Produces @myservice @WebServiceRef (lookup =" java: app/service/PaymentService ") {} @Inject @myservice MyWebService;' В этом случае контейнер не управляет жизненным циклом MyWebServiceImpl, он просто вводит его –