public class BookService {
··@Inject @ThirteenDigits
··private NumberGenerator numberGenerator;
··public Book createBook(String title, Float price, String description) {
····Book book = new Book(title, price, description);
····book.setIsbn(numberGenerator.generateNumber());
····return book;
··}
}
public class LegacyBookService {
··@Inject @EightDigits
··private NumberGenerator numberGenerator;
··public Book createBook(String title, Float price, String description) {
····Book book = new Book(title, price, description);
····book.setIsbn(numberGenerator.generateNumber());
····return book;
··}
}
Для того чтобы это работало, вам не нужна внешняя конфигурация. Поэтому говорят, что CDI использует строгую типизацию. Вы можете как угодно переименовать ваши реализации или квалификатор — точка внедрения не изменится (так называемая слабая связанность). Как видите, CDI — это аккуратный способ произвести внедрение с сохранением безопасности типов. Но если вы начнете создавать аннотации каждый раз, когда захотите что-либо внедрить, код вашего приложения в итоге чрезмерно разрастется. В этом случае вам помогут квалификаторы, используемые с членами.
Квалификаторы, используемые с членами. Каждый раз, когда вам необходимо выбирать из нескольких реализаций, вы создаете квалификатор (то есть аннотацию). Поэтому, если вам нужны две дополнительные цифры и десятизначный генератор чисел, вы создадите дополнительные аннотации (например, @TwoDigits, @EightDigits, @TenDigits, @ThirteenDigits). Представьте, что генерируемые числа могут быть как четными, так и нечетными. В итоге у вас получится множество разных аннотаций: @TwoOddDigits, @TwoEvenDigits, @EightOddDigits и т. д. Один из способов избежать умножения аннотаций — использовать члены.
В нашем примере мы смогли заменить все эти квалификаторы всего одним — @NumberOfDigits с перечислением в качестве значения и логическими параметрами для проверки четности (листинг 2.13).
@Qualifier
@Retention(RUNTIME)
@Target({FIELD, TYPE, METHOD})
public @interface NumberOfDigits {
··Digits value();
··boolean odd();
}
public enum Digits {
··TWO,
··EIGHT,
··TEN,
··THIRTEEN
}
Способ использования этого квалификатора не отличается от тех, которые вы видели раньше. Точка внедрения квалифицирует необходимую реализацию, располагая члены аннотации следующим образом:
@Inject @NumberOfDigits(value = Digits.THIRTEEN, odd = false)
private NumberGenerator numberGenerator;
Используемая реализация сделает то же самое:
@NumberOfDigits(value = Digits.THIRTEEN, odd = false)
public class IsbnEvenGenerator implements NumberGenerator {…}
Множественные квалификаторы. Другой способ квалифицировать компонент и точку внедрения — указать множественные квалификаторы. Так, вместо множественных квалификаторов для четности (@TwoOddDigits, @TwoEvenDigits) либо квалификатора, применяемого с членами (@NumberOfDigits), мы могли использовать два разных набора квалификаторов: один набор для четности (@Odd и @Even), другой — для количества цифр. Ниже приводится способ, которым вы можете квалифицировать генератор 13 четных чисел:
@ThirteenDigits @Even
public class IsbnEvenGenerator implements NumberGenerator {…}
Точка внедрения использовала бы тот же самый синтаксис:
@Inject @ThirteenDigits @Even
private NumberGenerator numberGenerator;
Тогда внедрению будет подлежать только компонент, имеющий обе аннотации квалификатора. Названия квалификаторов должны быть понятными. Для приложения важно, чтобы квалификаторы имели правильные имена и степень детализации.
Альтернативы
Квалификаторы позволяют выбирать между множественными реализациями интерфейса во время развертывания. Но иногда бывает целесообразно внедрить реализацию, зависящую от конкретного сценария развертывания. Например, вы решите использовать имитационный генератор чисел в тестовой среде.
Альтернативы — это компоненты, аннотированные специальным квалификатором javax.enterprise.inject.Alternative. По умолчанию альтернативы отключены, и чтобы сделать их доступными для инстанцирования и внедрения, необходимо активизировать их в дескрипторе beans.xml. В листинге 2.14 показана альтернатива имитационного генератора чисел.