@Alternative
public class TestCoderImpl implements Coder { ... }
Java Platform, Enterprise Edition (Java EE) 8 Учебник по Java EE |
Назад | Вперёд | Содержание |
Если у вас есть более одной версии бина, который вы используете для разных целей, вы можете выбирать между ними на этапе разработки, вводя тот или иной квалификатор, как показано в Примере 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, если оно есть.
Назад | Вперёд | Содержание |