До CDI в EJB 3 также вводилось внедрение зависимостей, но это было немного базовым. Вы можете добавить EJB (statefull или без сохранения состояния) в другой EJB или Servlet (если ваш контейнер поддерживает это). В Offcourse не каждое приложение нуждается в EJB, поэтому CDI приобретает такую большую популярность.
Для начала я сделал этот пример. Есть интерфейс оплаты и 2 реализации. Оплата наличными и виза.
Я хочу выбрать способ оплаты, который я использую, и при этом использовать тот же интерфейс:
1
2
3
|
public interface Payment { void pay(BigDecimal amount); } |
Вот 2 реализации:
1
2
3
4
5
6
7
8
9
|
public class CashPaymentImpl implements Payment { private static final Logger LOGGER = Logger.getLogger(CashPaymentImpl. class .toString()); @Override public void pay(BigDecimal amount) { LOGGER.log(Level.INFO, "payed {0} cash" , amount.toString()); } } |
1
2
3
4
5
6
7
8
9
|
public class VisaPaymentImpl implements Payment { private static final Logger LOGGER = Logger.getLogger(VisaPaymentImpl. class .toString()); @Override public void pay(BigDecimal amount) { LOGGER.log(Level.INFO, "payed {0} with visa" , amount.toString()); } } |
Чтобы добавить интерфейс, мы используем аннотацию @Inject . Аннотация делает в основном то, что говорит. Он внедряет компонент, который доступен в вашем приложении.
1
|
@Inject private Payment 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" ) public class CashPaymentImpl implements Payment { private static final Logger LOGGER = Logger.getLogger(CashPaymentImpl. class .toString()); @Override public void pay(BigDecimal amount) { LOGGER.log(Level.INFO, "payed {0} cash" , amount.toString()); } } |
01
02
03
04
05
06
07
08
09
10
|
@Named ( "visa" ) public class VisaPaymentImpl implements Payment { private static final Logger LOGGER = Logger.getLogger(VisaPaymentImpl. class .toString()); @Override public void pay(BigDecimal amount) { LOGGER.log(Level.INFO, "payed {0} with visa" , amount.toString()); } } |
Теперь, когда мы изменим наш код внедрения, мы можем указать, какая реализация нам нужна.
1
|
@Inject private @Named ( "visa" ) Payment payment; |
Это работает, но гибкость ограничена. Когда мы хотим переименовать наш параметр @Named, мы должны изменять его везде, где он используется. Также нет поддержки рефакторинга.
Есть лучшая альтернатива с использованием пользовательских аннотаций с использованием аннотации @Qualifier. Давайте немного изменим код.
Прежде всего, мы создаем новые типы аннотаций.
1
2
3
4
5
|
@java .lang.annotation.Documented @java .lang.annotation.Retention(RetentionPolicy.RUNTIME) @javax .inject.Qualifier public @interface CashPayment { } |
1
2
3
4
5
|
@java .lang.annotation.Documented @java .lang.annotation.Retention(RetentionPolicy.RUNTIME) @javax .inject.Qualifier public @interface VisaPayment { } |
Аннотация @Qualifier , добавляемая к аннотации, делает эту аннотацию видимой для контейнера. Теперь мы можем просто добавить эти аннотации к нашим реализациям.
01
02
03
04
05
06
07
08
09
10
|
@CashPayment public class CashPaymentImpl implements Payment { private static final Logger LOGGER = Logger.getLogger(CashPaymentImpl. class .toString()); @Override public void pay(BigDecimal amount) { LOGGER.log(Level.INFO, "payed {0} cash" , amount.toString()); } } |
01
02
03
04
05
06
07
08
09
10
|
@VisaPayment public class VisaPaymentImpl implements Payment { private static final Logger LOGGER = Logger.getLogger(VisaPaymentImpl. class .toString()); @Override public void pay(BigDecimal amount) { LOGGER.log(Level.INFO, "payed {0} with visa" , amount.toString()); } } |
Единственное, что нам теперь нужно сделать, это изменить наш код инъекции на
1
|
@Inject private @VisaPayment Payment payment; |
Когда мы теперь изменим что-то на наш классификатор, у нас будет хорошая поддержка компилятора и рефакторинга. Это также добавляет дополнительную гибкость для разработки API или языка, специфичного для предметной области .
Ссылка: Java EE6 CDI, именованные компоненты и квалификаторы от нашего партнера JCG Джелле Виктор из блога Styled Ideas .
- Декораторы Java EE6: декорирование классов во время внедрения
- События Java EE6: легкая альтернатива JMS
- Управление конфигурацией в Java EE
- Основные ссылки EJB, инъекция и поиск
- Модульные подходы Java — Модули, модули, модули
- Прошлое, настоящее и облако Java EE 7
- Список учебных пособий по Java и Android