#jakarta-ee #servlets #glassfish #ejb #scheduled-tasks
#Джакарта-ee #сервлеты #glassfish #ejb #запланированные задачи
Вопрос:
Мне нужно запланировать задачу в моем веб-приложении. Задача должна использовать поле элемента Servlet
, которое инициализируется во время развертывания. Я использовал EJB @Schedule
. Однако при запуске задачи поле участника равно нулю. Я предполагаю, что причина кроется в том факте, что мне пришлось добавить @Stateless
аннотацию к сервлету, чтобы выполнить @Schedule
работу, и мой сервлет действительно должен сохранять свое состояние?
Если да, как я могу запустить свою задачу простым и эффективным способом? Использование GlassFish 3
Вот снимок моего кода
@Stateless // <-- Wrong ??
public class myServlet extends GenericServlet {
private MemberField myMemberField = new MemberField();
@Override
public void init() throws ServletException {
myMemberField.initialize();
}
@Schedule(dayOfWeek = "Mon-Fri", hour = "21", minute = "59", second = "55")
public void myTask() {
System.out.println(myMemberField.toString());
}
// other stuff
}
Редактировать
В руководстве по Java EE говорится:
Служба таймера контейнера корпоративного компонента позволяет планировать уведомления по времени для всех типов корпоративных компонентов, за исключением сеансовых компонентов с отслеживанием состояния
Итак, я пришел к выводу, что этот способ не подходит для использования в a Servlet
.
ПРАВКА 2
Сервлет необходим для запуска службы CometD Bayeux: смотрите здесь, Почему. MyMemberField представляет собой уникальный экземпляр класса-оболочки, который обеспечивает взаимодействие с API брокера (это торговое приложение). Этот экземпляр класса-оболочки должен быть уникальным для всех сеансов и пользователей. Я инициализирую его на init()
сервлете. Этот класс-оболочка отправляет запросы брокеру и получает асинхронные ответы. Может быть, лучше определить этот класс вне конфигуратора Байе, но я не знаю, как его определить. Как сервлет? Как управляемый компонент? Кроме того, мне нужно работать с планировщиком, чтобы отправлять запланированные сообщения брокеру. Итак, запланированная задача должна знать об экземпляре класса-оболочки брокера.
Ответ №1:
Когда вы аннотируете сервлет @без состояния, вы создали два компонента JavaEE:
- Сервлет, управляемый webcontainer. Webcontainer, скорее всего, создаст один экземпляр класса для обслуживания всех запросов.
- Сеансовый компонент без состояния, управляемый контейнером EJB. Контейнер EJB, скорее всего, создаст несколько экземпляров класса и объединит их для обработки запросов EJB.
Когда сервлет обрабатывает первоначальный запрос, инициализируется поле экземпляра в сервлете. Когда выполняется @Schedule, поле экземпляра EJB инициализируется чем-то другим.
Моя рекомендация о том, как решить проблему, зависит от того, какие данные хранятся в поле экземпляра. Это данные инициализации для всего приложения? Если это так, то я бы создал отдельный класс @Singleton с @PostConstruct, который инициализирует данные экземпляра, а затем переместил @Schedule в этот класс. Это данные, зависящие от запроса? Если это так, то я бы использовал TimerService.createCalendarTimer и передал данные в метод timer через информационный параметр TimerConfig.
Кроме того, если вам не нужна гарантия того, что таймер «догонит» при остановке приложения или в случае сбоя JVM, тогда вы можете рассмотреть возможность использования непостоянного таймера.
Ответ №2:
@bkail попал в самую точку. Вы смешиваете концепции сервлетов и EJB. Разделите их на два отдельных класса.
@Singleton
public class FooTask {
private Foo foo;
@PostConstruct
public void init() {
foo = new Foo();
foo.initialize();
}
@Schedule(dayOfWeek = "Mon-Fri", hour = "21", minute = "59", second = "55")
public void run() {
System.out.println(foo);
// ...
}
public Foo getFoo() {
return foo;
}
}
Если вы по какой-то причине хотите иметь доступ foo
к каждому запросу сервлета, вам следует ввести его как @EJB
в свой сервлет.
@WebServlet("/foo/*")
public class FooServlet extends HttpServlet {
@EJB
private FooTask fooTask;
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
System.out.println(fooTask.getFoo());
// ...
}
}