• перехватчики обратного вызова жизненного цикла — перехватчик, который вмешивается в работу обратных вызовов событий жизненного цикла целевого экземпляра (@PostConstruct и @PreDestroy).
Примечание
Начиная с Java EE 6, перехватчики оформились в отдельную спецификацию (до этого они входили в состав спецификации EJB). Они могут применяться к управляемым компонентам, как вы увидите далее в этом разделе, а также к компонентам EJB и веб-службам SOAP и RESTful.
Перехватчики целевого класса
Существует несколько способов определения перехвата. Самый простой — добавить перехватчики (уровня метода, тайм-аута или жизненного цикла) к самому компоненту, как показано в листинге 2.23. Класс CustomerService сопровождает logMethod() аннотацией @AroundInvoke. Этот метод используется для регистрации сообщения во время входа в метод и выхода из него. Как только этот управляемый компонент развертывается, любой клиентский вызов createCustomer() или findCustomerById() будет перехватываться и начнет применяться logMethod(). Обратите внимание, что область видимости этого перехватчика ограничена самим компонентом (целевым классом).
Листинг 2.23. Класс CustomerService, использующий перехватчик, предшествующий вызову
@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 (InvocationContext ic) throws Exception;
Следующие правила относятся к методу, предшествующему вызову (а также конструктору, времени задержки или перехватчикам жизненного цикла):
• метод может иметь доступ public, private, protected либо доступ на уровне пакета, но не должно быть доступа static или final;
• метод должен иметь параметр javax.interceptor.InvocationContext и возвращать объект, который является результатом вызванного метода проб;
• метод может генерировать проверяемое исключение.
Объект InvocationContext позволяет перехватчикам контролировать поведение цепочки вызовов. Если несколько перехватчиков соединены в цепочку, то один и тот же экземпляр InvocationContext передается каждому перехватчику, который может добавить контекстуальные данные для обработки другими перехватчиками. Таблица 2.4 описывает API InvocationContext.
Таблица 2.4.Определение интерфейса InvocationContext
Метод |
Описание |
getContextData |
Позволяет значениям передаваться между методами перехвата в том же экземпляре InvocationContext с использованием Map |
getConstructor |
Возвращает конструктор целевого класса, для которого был вызван перехватчик |
getMethod |
Возвращает метод класса компонентов, для которого был вызван перехватчик |
getParameters |
Возвращает параметры, которые будут использоваться для вызова бизнес-метода |
getTarget |
Возвращает экземпляр компонента, к которому относится перехватываемый метод |
getTimer |
Возвращает таймер, ассоциированный с методом @Timeout |
proceed |
Обеспечивает вызов следующего метода перехватчика по цепочке. Он возвращает результат следующего вызываемого метода. Если метод относится к типу void, то proceed возвращает null |
setParameters |
Модифицирует значение параметров, используемых для вызова методов целевого класса. Типы и количество параметров должны совпадать с подписью метода компонента, иначе будет сгенерировано исключение IllegalArgumentException |
Чтобы понять, как работает код в листинге 2.23, взгляните на схему последовательности на рис. 2.6. Вы увидите, что происходит, когда клиент вызывает метод createCustomer(). Прежде всего контейнер перехватывает вызов и вместо прямой обработки createCustomer() сначала вызывает метод logMethod(). Данный метод использует интерфейс InvocationContext для получения имени вызываемого компонента (ic.getTarget()), а вызываемый метод (ic.getMethod()) применяет для регистрации сообщения о входе (logger.entering()). Затем вызывается метод proceed(). Вызов InvocationContext.proceed() очень важен, поскольку сообщает контейнеру, что тот должен обрабатывать следующий перехватчик или вызывать бизнес-метод компонента. При отсутствии вызова proceed() цепочка перехватчиков будет остановлена, а бизнес-метод не будет вызван. В конце вызывается метод createCustomer(), и как только он возвращается, перехватчик прекращает выполнение, регистрируя сообщение о выходе (logger.exiting()). Вызов клиентом метода findCustomerById() происходил бы в той же последовательности.
Читать дальше