До CDI в EJB 3 также вводилось внедрение зависимостей, но это было немного базовым. Вы можете добавить EJB (statefull или без сохранения состояния) в другой EJB или Servlet (если ваш контейнер поддерживает это). В Offcourse не каждое приложение нуждается в EJB, поэтому CDI приобретает такую большую популярность.
Для начала я сделал этот пример. Есть интерфейс оплаты и 2 реализации. Оплата наличными и виза.
Я хочу выбрать способ оплаты, который я использую, и при этом использовать тот же интерфейс:
| 1 2 3 | publicinterfacePayment {    voidpay(BigDecimal amount);} | 
Вот 2 реализации:
| 1 2 3 4 5 6 7 8 9 | publicclassCashPaymentImpl implementsPayment {     privatestaticfinalLogger LOGGER = Logger.getLogger(CashPaymentImpl.class.toString());     @Override    publicvoidpay(BigDecimal amount) {        LOGGER.log(Level.INFO, "payed {0} cash", amount.toString());    }} | 
| 1 2 3 4 5 6 7 8 9 | publicclassVisaPaymentImpl implementsPayment {     privatestaticfinalLogger LOGGER = Logger.getLogger(VisaPaymentImpl.class.toString());     @Override    publicvoidpay(BigDecimal amount) {        LOGGER.log(Level.INFO, "payed {0} with visa", amount.toString());    }} | 
Чтобы добавить интерфейс, мы используем аннотацию @Inject . Аннотация делает в основном то, что говорит. Он внедряет компонент, который доступен в вашем приложении.
| 1 | @InjectprivatePayment payment; | 
Конечно, вы видели, как это происходит за милю, это не сработает. Контейнер имеет 2 реализации нашего интерфейса Payment, поэтому он не знает, какой из них ввести.
Неудовлетворенные зависимости для типа [Payment] с квалификаторами [@Default] в точке внедрения [[field] @Inject private be.styledideas.blog.qualifier.web.PaymentBackingAction.payment]
Поэтому нам нужен какой-то классификатор, чтобы указать, какую реализацию мы хотим. CDI предлагает аннотацию @Named , позволяющую дать имя реализации.
| 01 02 03 04 05 06 07 08 09 10 | @Named("cash")publicclassCashPaymentImpl implementsPayment {     privatestaticfinalLogger LOGGER = Logger.getLogger(CashPaymentImpl.class.toString());     @Override    publicvoidpay(BigDecimal amount) {        LOGGER.log(Level.INFO, "payed {0} cash", amount.toString());    }} | 
| 01 02 03 04 05 06 07 08 09 10 | @Named("visa")publicclassVisaPaymentImpl implementsPayment {     privatestaticfinalLogger LOGGER = Logger.getLogger(VisaPaymentImpl.class.toString());     @Override    publicvoidpay(BigDecimal amount) {        LOGGER.log(Level.INFO, "payed {0} with visa", amount.toString());    }} | 
Теперь, когда мы изменим наш код внедрения, мы можем указать, какая реализация нам нужна.
| 1 | @Injectprivate@Named("visa") Payment payment; | 
Это работает, но гибкость ограничена. Когда мы хотим переименовать наш параметр @Named, мы должны изменять его везде, где он используется. Также нет поддержки рефакторинга.
Есть лучшая альтернатива с использованием пользовательских аннотаций с использованием аннотации @Qualifier. Давайте немного изменим код.
Прежде всего, мы создаем новые типы аннотаций.
| 1 2 3 4 5 | @java.lang.annotation.Documented@java.lang.annotation.Retention(RetentionPolicy.RUNTIME)@javax.inject.Qualifierpublic@interfaceCashPayment {} | 
| 1 2 3 4 5 | @java.lang.annotation.Documented@java.lang.annotation.Retention(RetentionPolicy.RUNTIME)@javax.inject.Qualifierpublic@interfaceVisaPayment {} | 
Аннотация @Qualifier , добавляемая к аннотации, делает эту аннотацию видимой для контейнера. Теперь мы можем просто добавить эти аннотации к нашим реализациям.
| 01 02 03 04 05 06 07 08 09 10 | @CashPaymentpublicclassCashPaymentImpl implementsPayment {     privatestaticfinalLogger LOGGER = Logger.getLogger(CashPaymentImpl.class.toString());     @Override    publicvoidpay(BigDecimal amount) {        LOGGER.log(Level.INFO, "payed {0} cash", amount.toString());    }} | 
| 01 02 03 04 05 06 07 08 09 10 | @VisaPaymentpublicclassVisaPaymentImpl implementsPayment {     privatestaticfinalLogger LOGGER = Logger.getLogger(VisaPaymentImpl.class.toString());     @Override    publicvoidpay(BigDecimal amount) {        LOGGER.log(Level.INFO, "payed {0} with visa", amount.toString());    }} | 
Единственное, что нам теперь нужно сделать, это изменить наш код инъекции на
| 1 | @Injectprivate@VisaPaymentPayment payment; | 
Когда мы теперь изменим что-то на наш классификатор, у нас будет хорошая поддержка компилятора и рефакторинга. Это также добавляет дополнительную гибкость для разработки API или языка, специфичного для предметной области .
Ссылка: Java EE6 CDI, именованные компоненты и квалификаторы от нашего партнера JCG Джелле Виктор из блога Styled Ideas .
- Декораторы Java EE6: декорирование классов во время внедрения
- События Java EE6: легкая альтернатива JMS
- Управление конфигурацией в Java EE
- Основные ссылки EJB, инъекция и поиск
- Модульные подходы Java — Модули, модули, модули
- Прошлое, настоящее и облако Java EE 7
- Список учебных пособий по Java и Android