Java Platform, Enterprise Edition (Java EE) 8
Учебник по Java EE

Назад Вперёд Содержание

Использование альтернатив в приложениях CDI

Если у вас есть более одной версии бина, который вы используете для разных целей, вы можете выбирать между ними на этапе разработки, вводя тот или иной квалификатор, как показано в Примере simplegreeting на CDI.

Однако вместо изменения исходного кода вашего приложения вы можете сделать выбор во время развёртывания, используя альтернативные варианты.

Альтернативы обычно используются для следующих целей:

  • Для обработки клиентской бизнес-логики, которая определяется во время выполнения

  • Чтобы указать компоненты, валидные для конкретного сценария развёртывания (например, когда законодательство о налоге с продаж для конкретной страны требует специальной бизнес-логики)

  • Чтобы создать фиктивные версии бинов для тестирования.

Чтобы сделать компонент доступным для механизмов EL, JNDI или инъецирования, аннотируйте его javax.enterprise.inject.Alternative, а затем используйте элемент alternatives, чтобы указать это в файле beans.xml.

Например, вы можете создать полную версию компонента, а также более простую версию, которую вы используете только для определённых видов тестирования. Пример, описанный в Пример encoder: использование альтернатив, содержит два таких бина: CoderImpl и TestCoderImpl. Тестовый компонент помечается следующим образом:

@Alternative
public class TestCoderImpl implements Coder { ... }

Полная версия не аннотирована:

public class CoderImpl implements Coder { ... }

Managed-бин инъецирует объект интерфейса Coder:

@Inject
Coder coder;

Альтернативная версия компонента используется приложением, только если эта версия объявлена ​​в файле beans.xml следующим образом:

<beans ...>
    <alternatives>
        <class>javaeetutorial.encoder.TestCoderImpl</class>
    </alternatives>
</beans>

Если элемент alternatives закомментирован в файле beans.xml, используется класс CoderImpl.

Вы также можете иметь несколько бинов, аннотированных @Alternative и реализующих один и тот же интерфейс. В этом случае нужно указать в файле beans.xml, какой из этих альтернативных компонентов должен использоваться. Если бы CoderImpl также был аннотирован @Alternative, один из двух бинов всегда должен быть указан в файле beans.xml.

Альтернативы, указанные в файле beans.xml, применяются только к классам в одном и том же архиве. Используйте аннотацию @Priority, чтобы глобально указать альтернативы для приложения, состоящего из нескольких модулей, как в следующем примере:

@Alternative
@Priority(Interceptor.Priority.APPLICATION+10)
public class TestCoderImpl implements Coder { ... }

Если существует несколько альтернативных бинов, реализующих один и тот же интерфейс, помеченных @Priority, то выбирается альтернатива с более высоким значением приоритета. Когда используется аннотация @Priority, указывать альтернативу в файле beans.xml не обязательно.

Использование специализации

Специализация выполняет ту же функцию, что и альтернатива, то есть позволяет заменять один компонент на другой. Вам может потребоваться сделать так, чтобы один бин переопределял другой во всех случаях. Предположим, вы определили следующие два компонента:

@Default @Asynchronous
public class AsynchronousService implements Service { ... }

@Alternative
public class MockAsynchronousService extends AsynchronousService { ... }

Если затем вы объявили MockAsynchronousService в качестве альтернативы в вашем файле beans.xml, следующая точка инъецирования будет преобразована в MockAsynchronousService:

@Inject Service service;

Следующее, однако, разрешит AsynchronousService, а не MockAsynchronousService, потому что MockAsynchronousService не имеет квалификатора @Asynchronous :

@Inject @Asynchronous Service service;

Чтобы убедиться, что MockAsynchronousService всегда инъецировался, необходимо реализовать все типы бинов и квалификаторы бина AsynchronousService. Однако, если AsynchronousService объявил метод-производитель или метод-наблюдатель, даже этот громоздкий механизм не гарантирует, что другой компонент никогда не будет вызван. Специализация обеспечивает более простой механизм.

Специализация происходит как во время разработки, так и во время выполнения. Если вы объявляете, что один компонент специализирует другой, он расширяет класс другого компонента, и во время выполнения специализированный компонент полностью заменяет этот другой компонент. Если первый компонент создаётся методом-производителем, вы также должны переопределить метод-производитель.

Специализация компонента определяется аннотацией javax.enterprise.inject.Specializes. Например, вы можете объявить бин следующим образом:

@Specializes
public class MockAsynchronousService extends AsynchronousService { ... }

В этом случае класс MockAsynchronousService всегда будет вызываться вместо класса AsynchronousService.

Обычно бин, помеченный аннотацией @Specializes, также является альтернативой и объявляется как альтернатива в файле beans.xml. Такой компонент предназначен для замены реализации по умолчанию, а альтернативная реализация автоматически наследует все квалификаторы реализации по умолчанию, а также его имя EL, если оно есть.


Назад Вперёд Содержание
Логотип Oracle  Copyright © 2017, Oracle и/или её дочерних компаний. Все права защищены. Версия перевода 1.0.5 (Java EE Tutorial — русскоязычная версия)