public class ProfileInterceptor {

··@Inject

··private Logger logger;

··@PostConstruct

··public void logMethod(InvocationContext ic) throws Exception {

····logger.fine(ic.getTarget(). toString());

····try {

······ic.proceed();

····} finally {

······logger.fine(ic.getTarget(). toString());

····}

··}

··@AroundInvoke

··public Object profile(InvocationContext ic) throws Exception {

····long initTime = System.currentTimeMillis();

····try {

······return ic.proceed();

····} finally {

······long diffTime = System.currentTimeMillis() — initTime;

······logger.fine(ic.getMethod() + " took " + diffTime + " millis");

····}

··}

}

Как видно из листинга 2.26, перехватчики жизненного цикла берут параметр InvocationContext и вместо Object возвращают void. Чтобы применить перехватчик, определенный в листинге 2.26, компонент CustomerService (листинг 2.27) должен использовать аннотацию @Interceptors и определять ProfileInterceptor. Если компонент инстанцируется контейнером, метод logMethod() будет вызван раньше метода init(). Затем, если клиент вызывает createCustomer() или findCustomerById(), будет вызван метод profile().

Листинг 2.27. CustomerService, использующий перехватчик и аннотацию обратного вызова

@Transactional

@Interceptors(ProfileInterceptor.class)

public class CustomerService {

··@Inject

··private EntityManager em;

··@PostConstruct

··public void init() {

····//…

··}

··public void createCustomer(Customer customer) {

····em.persist(customer);

··}

··public Customer findCustomerById(Long id) {

····return em.find(Customer.class, id);

··}

}

<p>Связывание и исключение перехватчиков</p>

Вы уже видели, как перехватываются вызовы в пределах одного компонента (с аннотацией @Around Invoke), а также среди множественных компонентов (с использованием аннотации @Interceptors). Спецификация Interceptors 1.2 также позволяет связать в цепочку несколько перехватчиков.

В действительности аннотация @Interceptors способна прикреплять более одного перехватчика, так как в качестве параметра она берет список перехватчиков, разделенных запятой. Когда определяются множественные перехватчики, порядок их вызова задается тем порядком, в котором они указаны в аннотации @Interceptors. Например, код в листинге 2.28 использует аннотацию @Interceptors у компонента и на уровне методов.

Листинг 2.28. CustomerService, соединяющий несколько перехватчиков

@Stateless

@Interceptors({I1.class, I2.class})

public class CustomerService {

··public void createCustomer(Customer customer) {…}

··@Interceptors({I3.class, I4.class})

··public Customer findCustomerById(Long id) {…}

··public void removeCustomer(Customer customer) {…}

··@ExcludeClassInterceptors

··public Customer updateCustomer(Customer customer) {…}

}

Когда клиент вызывает метод updateCustomer(), перехватчик не вызывается, так как метод аннотирован @ExcludeClassInterceptors. При вызове метода createCustomer() выполняется перехватчик I1, за которым следует перехватчик I2. При вызове метода findCustomerById() перехватчики I1, I2, I3 и I4 выполняются в соответствующем порядке.

<p>Связывание с перехватчиком</p>

Перехватчики определяются в своей собственной спецификации (запрос JSR 318) и могут использоваться в любых управляемых компонентах (EJB, сервлетах, веб-службах RESTful и т. д.). Но CDI расширил исходную спецификацию, добавив к ней связывание с перехватчиком. Это означает, что связывание с перехватчиком может применяться только тогда, когда активизирован CDI.

Перейти на страницу:

Похожие книги