Как реализовать перехватчик в таймере в Джакарте EE9

#jakarta-ee #timer #ejb #interceptor #stateless-session-bean

Вопрос:

Я хочу иметь компонент сеанса без состояния в JAKARTA EE9, где я печатаю «привет» на консоли каждые 10 секунд. Это достигается с помощью следующего кода.

 @jakarta.ejb.Stateless(name = "MyTimerEJB")
public class MyTimerBean {
    @Schedule(hour ="*", minute = "*", second = "*/10")
    public void printTime() {
        System.out.println("good day");
    }
}
 

Но теперь я также хочу добавить перехватчик, который перехватывает это по субботам и воскресеньям, а затем печатает «хороших выходных». Я перепробовал кучу вещей, но, похоже, ничего не работает. К сожалению, документация также немного ограничена.

Ответ №1:

Если вы ознакомитесь со спецификациями EJB, раздел 7.4, вы узнаете об AroundTimeout аннотации.

Короче говоря, все, что вам нужно, — это обычный, включенный перехватчик для интересующего вас компонента с аннотированным методом @AroundTimeout .

Сказав это, я надеюсь, что описанный вами вариант использования является лишь примером. На самом деле я считаю плохой практикой использовать перехватчик для столь радикального изменения поведения программы, как вы описываете. Мне было бы очень трудно рассуждать о функциональности такой программы. Перехватчики хороши для реализации сквозных задач (например, транзакций, ведения журнала, авторизации), которые не нарушают основную логику перехваченного кода.

Если бы я реализовал этот вариант использования, я бы:

  • Создайте SayHello компонент CDI, который может знать, как решить, какое сообщение выводить в зависимости от дня (или любого другого)
    • Предпочтительно, я бы реализовал функцию «часы» в другом компоненте, который я могу использовать для модульных тестов
  • Используйте планировщик только для вызова SayHello , не более

Поскольку это оказалось полезным, я кратко повторяю основные моменты руководства JEE по перехватчикам:

ВНИМАНИЕ: ниже приводится краткое резюме, пожалуйста, следуйте учебным пособиям и документации для конкретного использования

Чтобы определить перехватчик, используйте одну из аннотаций метаданных перехватчика: javax.interceptor.AroundConstruct , javax.interceptor.AroundInvoke , javax.interceptor.AroundTimeout , javax.annotation.PostConstruct , javax.annotation.PreDestroy для метода, определенного для компонента, который будет распознан контейнером. Это может быть тот же компонент, что и компонент, содержащий перехваченный метод, или другой.

Если перехватчик относится к другому классу, используйте javax.interceptor.Interceptors его для активации. Эта аннотация может относиться к определенному методу или ко всему классу, и в этом случае перехватываются все бизнес-методы. Помните, что перехватчики не влияют на методы, не относящиеся к бизнесу (частные/защищенные методы определенно НЕ относятся к бизнесу и являются распространенной ошибкой). Перехватчики НЕ вступают в силу при бизнес-вызове методов this объекта, еще одна очень распространенная ошибка, будьте осторожны!

В качестве альтернативы вы можете определить аннотацию привязки перехватчика, например (из учебника):

 @InterceptorBinding // this makes it an interceptor binding annotation
@Target({TYPE, METHOD})
@Retention(RUNTIME)
@Inherited
pubic @interface Logged { ... }
 

Теперь аннотирование класса или метода с @Logged помощью активирует перехватчик, определенный как:

 @Logged
@Interceptor
public class LoggingInterceptor {
    @AroundInvoke
    public Object logInvocation(InvocationContext ctx) throws Exception {
        ...
    }
    ...
}
 

Чтобы фактически активировать перехватчик, вам необходимо использовать дескриптор развертывания (в зависимости от того, используете ли вы его на EJB или CDI или на обоих) или использовать @Priority аннотацию.

Комментарии:

1. Да, это только для примера, чтобы он был реализован и работал. Спасибо!

2. Я все равно предпочел бы реализовать логику в компонентах CDI (и применить к ним любые необходимые перехватчики) и оставить планировщик как можно более простым. В любом случае удачи!

3. Если у вас есть лучшая/более простая идея реализации перехватчика, я рад ее услышать. Логика в данный момент не важна, мне просто нужно уметь использовать перехватчик 🙂

4. Боюсь, что если вам действительно нужен перехватчик, то @AroundTimeout это единственный способ, который я могу придумать. Смотри здесь .