• перехватчики, действующие на уровне конструктора, — перехватчик, ассоциированный с конструктором целевого класса (@AroundConstruct);
• перехватчики, действующие на уровне метода, — перехватчик, ассоциированный со специальным бизнес-методом (@AroundInvoke);
• перехватчики методов задержки — перехватчик, помеченный аннотацией @AroundTimeout, вмешивается в работу методов задержки (применяется только со службой времени EJB, см. главу 8);
• перехватчики обратного вызова жизненного цикла — перехватчик, который вмешивается в работу обратных вызовов событий жизненного цикла целевого экземпляра (@PostConstruct и @PreDestroy).
Начиная с Java EE 6, перехватчики оформились в отдельную спецификацию (до этого они входили в состав спецификации EJB). Они могут применяться к управляемым компонентам, как вы увидите далее в этом разделе, а также к компонентам EJB и веб-службам SOAP и RESTful.
Перехватчики целевого класса
Существует несколько способов определения перехвата. Самый простой — добавить перехватчики (уровня метода, тайм-аута или жизненного цикла) к самому компоненту, как показано в листинге 2.23. Класс CustomerService сопровождает logMethod() аннотацией @AroundInvoke. Этот метод используется для регистрации сообщения во время входа в метод и выхода из него. Как только этот управляемый компонент развертывается, любой клиентский вызов createCustomer() или findCustomerById() будет перехватываться и начнет применяться logMethod(). Обратите внимание, что область видимости этого перехватчика ограничена самим компонентом (целевым классом).
@Transactional
public class CustomerService {
··@Inject
··private EntityManager em;
··@Inject
··private Logger logger;
··public void createCustomer(Customer customer) {
····em.persist(customer);
··}
··public Customer findCustomerById(Long id) {
····return em.find(Customer.class, id);
··}
··@AroundInvoke
··private Object logMethod(InvocationContext ic) throws Exception {
····logger.entering(ic.getTarget(). toString(), ic.getMethod(). getName());
····try {
······return ic.proceed();
····} finally {
······logger.exiting(ic.getTarget(). toString(), ic.getMethod(). getName());
····}
··}
}
Несмотря на аннотацию @AroundInvoke, logMethod() должен иметь следующий образец подписи:
@AroundInvoke
Object <METHOD>(InvocationContext ic) throws Exception;
Следующие правила относятся к методу, предшествующему вызову (а также конструктору, времени задержки или перехватчикам жизненного цикла):
• метод может иметь доступ public, private, protected либо доступ на уровне пакета, но не должно быть доступа static или final;
• метод должен иметь параметр javax.interceptor.InvocationContext и возвращать объект, который является результатом вызванного метода проб;
• метод может генерировать проверяемое исключение.
Объект InvocationContext позволяет перехватчикам контролировать поведение цепочки вызовов. Если несколько перехватчиков соединены в цепочку, то один и тот же экземпляр InvocationContext передается каждому перехватчику, который может добавить контекстуальные данные для обработки другими перехватчиками. Таблица 2.4 описывает API InvocationContext.
| Метод | Описание |
|---|---|
| getContextData | Позволяет значениям передаваться между методами перехвата в том же экземпляре InvocationContext с использованием Map |
| getConstructor | Возвращает конструктор целевого класса, для которого был вызван перехватчик |
| getMethod | Возвращает метод класса компонентов, для которого был вызван перехватчик |
| getParameters | Возвращает параметры, которые будут использоваться для вызова бизнес-метода |
| getTarget | Возвращает экземпляр компонента, к которому относится перехватываемый метод |
| getTimer | Возвращает таймер, ассоциированный с методом @Timeout |
| proceed | Обеспечивает вызов следующего метода перехватчика по цепочке. Он возвращает результат следующего вызываемого метода. Если метод относится к типу void, то proceed возвращает null |
| setParameters | Модифицирует значение параметров, используемых для вызова методов целевого класса. Типы и количество параметров должны совпадать с подписью метода компонента, иначе будет сгенерировано исключение IllegalArgumentException |