ru_java


ru.java

все о языке программирования java


Previous Entry Share Next Entry
Schedule in servlet
Снайпер
v_y_v wrote in ru_java
Прошу помощи в таком вопросе:
Есть Servlet, при инициализации он запускает таймер timer.schedule(actionclass,...) передавая ему некоторый actionclass, метод run которого и будет запускаться с заданным интервалом.
А вот как их этого Run запустить один из методов самого сервлета, т.е. получить доступ к методам и переменным?

А вы уверены что так правильно? На сколько я помню, то сервлеты могут создаваться и удаляться контейнером в любой момент за ненадобностью.

Ну а если очень надо, то тогда можно передавать, например не Class, а инстанс, т.е. new ActionClass(this)
или в timer делать поле, которое ссылается на сервлет и при запуске передавать его в ActionClass, например:
Timer.execute() {
ActionClass clazz = Class.forName("com.acme.ActionClass");
Object o = class.newInstance();
o.getMethod("run", new Object[] {Servlet.class}).invoke(this.servlet)
}

Спасибо, думаю в этом направлении и попробую.
Если сервлет выгрузится - то он уже никому не нужен, и следовательно таймер тоже.

Если мне память не изменяет, то контейнер может создавать несколько инстансов одного сервлета, при этом от одного и того же веб клиента один запрос будет обрабатываться одним инстансом, второй -- другим, потом первый инстанс может вообще быть удалён, затем третий запрос опять обработается вторым инстансом, на четвёртый запрос окажется создан четвёртый инстанс....

... и тут запуститя ваш экшен класс, который зачем-то захочет вызвать что-то у первого инстанса. И вызовет -- инстан в gc не ушёл, потому что его держит ваш экшен. Но то, что сделает ваш экшн с инстансом сервлета уже никто и никогда не узнает. Потому что контейнейр про этот инстанс уже ничего не знает и запросы к нему никогда больше не придут.

Насколько я понимаю, контейнер создает на каждый вызов сервлета свой экземляр, но вот методы остаются общими и переменные тоже.
И общий массив доступен всем экземплярам.
Следовательно мне из метода таймера необходимо обнулить один из элементов этого массива.

"Переменные" остаются общими только если это статические поля. Если это обычные поля -- они свои у каждого инстанса. Грубо говоря статические поля принадлежат самому классу, не статические -- экземпляру класса, который создаётся либо оператором new, либо вызовом clazz.newInstance()

Если "общий массив" не статический, то он доступен только "своему" экземпляру. А у "чужого" экземпляра -- своя копия массива.

> Насколько я понимаю, контейнер создает на каждый вызов сервлета свой экземляр,

Так тоже может быть. Но на сколько я помню, в общем случае это совсем не так. В общем случае все запросы могут выполняться одним инстансом. Или контейнер может создать пул потоков-воркеров с инстансами, и выполнять запросы конвеерно в несколько потоков, вытаскивая по мере освобождения воркер из пула и загружая его выполнением запроса.

изменяет. один контейнер содержит один экземпляр сервлета (никогда не видел, чтобы кто-то включал Single-Threaded Model)

Точно так же, как любой другой метод любого другого класса вызывает любой метод любого инстанса любого другого класса. То есть вам так или иначе нужен инстанс вашего сервлета в инстансе вашего actionclass'а

Но есть у меня какое-то нехорошее ощущение... Вы не могли бы подробнее описать, что конкретно вы пытаетесь сделать и хотите получить?

Промежуточная авторизация, без БД.
Таймер нужен для logout-а автоматического.
Понимаю, что правильней написать сервер и связку сервлет-сервер, но это достаточно громоздко будет.

В инстансе сервлета нельзя хранить никакую информацию, связанную с какими-либо данными клиента. Нет никакой гарантии, что следующий запрос клиента будет выполнять тот же самый инстанс сервлета и что тот инстанс, который выполнял предыдущий запрос, будет ещё жив.

Более того, запрос от другого клиента с высокой вероятностью выполнится тем же инстансом, который выполнял запрос от первого клиента. И если в первом запросе вы проводили аутентификацию и сохраняли данные об этом в инстансе сервлета, то пройднной первым клиентом аутентификацией воспользуется второй клиент.

Для того, что вы хотите, существует специальный контейнер javax.servlet.http.HttpSession, инстанс которого доступен в сервлете через параметр HTTPServletRequest в методах get/put/etc

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

При этом её протуханием можно управлять без введения дополнительных таймеров -- есть сешн таймаут, после которого сессия сбрасывается.

У меня промежуточная авторизация, а не прямая, поэтому привязка к клиенту сделана несколько по-иному. По поводу механизма работы контейнера я так ничего и ни нашел, пока работает без сбоев.
По javax.servlet.http.HttpSession видел но не пробовал.
Спасибо - буду теперь по поводу этого думать.
Прикрчивание таймаута сессии я смутно представляю себе в моем случае.

Ппц. Вы хоть читали спеку на сервлеты? Печально всё это...

А что Вы порекомендуете почитать по данному вопросу - понятное, а не задвинутое?
Пока ничего кроме простых вариантов работы с сервлетами я не нашел.

Для простых вещей вроде принять и обработать запрос вполне подойдут понятные форумы и небольшие куски кода примеров.
Вы же делаете совсем не то для чего были созданы сервлеты. Выше подсказали про javax.servlet.http.HttpSession я думаю этого вполне будет достаточно.

Однако "задвинутое" придётся по любому читать потому что спецификации на технологии Java стараются писать наиболее полными. И именно с них пишут реализации контейнеров.

Собственно ссылка:
http://jcp.org/aboutJava/communityprocess/mrel/jsr154/index2.html

PS: Вы упомянули термин "промежуточная авторизация". Мне сложно судить о суте задачи, но опять же существует множество различных стандартных механизмов авторизации. Как вариант например через web.xml + JAAS.

Спасибо за ссылку.
Да я понимаю, что я нарушаю концепцию, но разрастания бутерброда я еще больше боюсь.

обратите внимание на комментарий xeye - он прав, один экземпляр сервлета на jvm (SingleThreadModel является deprecated в servlet 2.5 поэтому даже и не думайте его использовать)