#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
это единственный способ, который я могу придумать. Смотри здесь .