EJB @Schedule проблема - PullRequest
       49

EJB @Schedule проблема

2 голосов
/ 08 октября 2011

Мне нужно запланировать задачу в моем веб-приложении.Задача должна использовать поле члена Servlet, которое инициализируется во время развертывания.Я использовал EJB @Schedule.Однако, когда задача запускается, поле члена имеет значение null.Я предполагаю, что причина заключается в том, что мне пришлось добавить аннотацию @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 написано:

Служба таймера контейнера EJB позволяет планировать уведомления по расписанию для всех типов EJB, за исключением сеансовых EJB с состоянием

. Поэтому я пришел к выводу, что этот способ не подходит для использования в Servlet.


EDIT 2

Сервлет необходим для запуска службы CometD Bayeux: см. здесь почему.MyMemberField представляет уникальный экземпляр класса-оболочки, который заботится о взаимодействии с API брокера (это торговое приложение).Этот экземпляр класса-оболочки должен быть уникальным для всех сеансов и пользователей.Я инициализирую его на init() сервлета.Этот класс-оболочка отправляет запросы брокеру и получает асинхронные ответы.Может быть, лучше определить этот класс за пределами конфигуратора Bayeux, но я не знаю, как его определить.Как сервлет?Как управляемый боб?Кроме того, мне нужно работать с планировщиком, чтобы отправлять запланированные сообщения посреднику.Таким образом, запланированное задание должно знать о экземпляре класса-посредника брокера.

Ответы [ 2 ]

4 голосов
/ 08 октября 2011

Когда вы аннотируете сервлет @Stateless, вы создали два компонента JavaEE:

  1. Сервлет, управляемый веб-контейнером.Скорее всего, веб-контейнер создаст один экземпляр класса для обслуживания всех запросов.
  2. Сессионный компонент без сохранения состояния, управляемый контейнером EJB.Контейнер EJB, скорее всего, создаст несколько экземпляров класса и объединит их в пул для обработки запросов EJB.

Когда сервлет обрабатывает первоначальный запрос, поле экземпляра в сервлете инициализируется.Когда выполняется @Schedule, поле экземпляра EJB инициализируется чем-то другим.

Моя рекомендация о том, как решить проблему, зависит от того, какие данные хранятся в поле экземпляра.Это данные инициализации всего приложения?Если это так, то я бы создал отдельный класс @Singleton с @PostConstruct, который инициализирует данные экземпляра, а затем переместил бы @Schedule в этот класс.Это зависимые от запроса данные?Если это так, то я бы использовал TimerService.createCalendarTimer и передавал данные методу таймера с помощью информационного параметра TimerConfig.

В качестве отступления, если вам не требуется гарантия, что таймер «поймает»вверх ", пока приложение остановлено или если JVM дает сбой, возможно, вы захотите использовать непостоянный таймер.

1 голос
/ 08 октября 2011

@ bkail ударил гвоздь по голове.Вы смешиваете концепции Servlet и 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());
        // ...
    }

}
...