Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > Java EE (J2EE) и Spring > Как "убить" или остановить сервлет вручную?


Автор: olegrolik 30.11.2007, 16:25
Есть веб приложение, есть два сервлета, которые работают. Первый  что-то выполняет (отправляет, принимает и т.д.). Второй нужен для того, чтобы при его запуске убить первый (или хотя бы остановить - если остановка возможна конечно). 
Как это можно реализовать?

Есть кое-какие мысли и соображения:
Например второй сервлет ищет инстанс первого и убивает его.

Забегая вперёд, хочу спросить, можно ли таким же образом осуществить запуск первого сервлета? Т.е. в зависимости от параметра запускать/останавливать первый ?

Спасибо.

Автор: Maksym 30.11.2007, 16:47
Цитата(olegrolik @  30.11.2007,  15:25 Найти цитируемый пост)
Т.е. в зависимости от параметра запускать/останавливать первый ?

Что ты понимаешь под запускать/останавливать? enable/disable.. что то другое?
И зачем "убивать сервлет"?

Автор: olegrolik 30.11.2007, 17:24
Maksym, понимаю создать инстанс/убить инстанс. Для начала так.
Убивать сервлет, для того, чтобы он ничего не делал  smile такая задача  smile  Конечно можно не убивать, а(повторяюсь) хотя бы остановить - не знаю возможно ли это.


-----------------------------------------------------------

Хм.... а вообще я тут ступил конкретно.... 
Можно ведь сделать что-то вроде такого:
 
Код

public void doGet(HttpServletRequest req, HttpServletResponse res) {
       String actionStr = request.getParameter("action");
       if(actionStr.equals("shutdown") this.destroy();

}

Автор: Souljah 30.11.2007, 17:52
Опиши задачу поточнее.
Что значит "ничего не делал"? Чтобы перестал отзываться на url-mapping к нему?

Менеджментом инстансов сервлетов заведует контейнер, убить сервлет без правки контейнерного кода не получится никак

Автор: Maksym 30.11.2007, 17:59
Цитата(olegrolik @  30.11.2007,  16:24 Найти цитируемый пост)
Хм.... а вообще я тут ступил конкретно.... 
Можно ведь сделать что-то вроде такого:

Ты пробовал после этого отправить запрос на сервлет..?
Я не тестил, но вроде как этот метод должн дергаться контейнером и открыт в API, чтобы в нем ресурсы освобождать, контейнер может протупить твой вызов и не заблокировать следующее обращение к service... 

Автор: COVD 30.11.2007, 19:42
Речь очевидно о том, что надо остановить поток, обслуживающий запрос клиента. Клиентов в общем случае много и потоков столько же (а сервлет один, про него вообще можно забыть, это всего лишь описание последовательности действий, "виртуальная функция" smile ).  

Клиент послал запрос. На сервере создался новый поток (или свободный из пула взят) и стал его выполнять. Клиент устал ждать и нажимает кнопку "Отменить". Сервер получает новый запрос "отменить" (очевидно, обрабатывается другим сервлетом). Опять создается новый поток, чтобы выполнить эту команду, т.е. остановить первый поток. Чтобы остановить выполнение первого потока надо предусмотреть в его шагах условия остановки, т.е. контрольную точку, флаг, которую он периодически проверяет, не слишком ли долго он копается с обработкой. Если да, то поток прекращает выполнение и закрывает соединение или шлет код ошибки. А второй поток, отменяющий, должен иметь доступ к этому флагу. Если бы клиент предполагался всегда один, то этот флаг можно было бы сделать статическим. Но если клиентов одновременно может быть много, то этот флаг должен быть в сессии клиента, чтобы клиент не отменил чужой запрос. 

Автор: olegrolik 2.12.2007, 23:43
Цитата(COVD @ 30.11.2007,  19:42)
Речь очевидно о том, что надо остановить поток, обслуживающий запрос клиента. Клиентов в общем случае много и потоков столько же (а сервлет один, про него вообще можно забыть, это всего лишь описание последовательности действий, "виртуальная функция" smile ).  

Клиент послал запрос. На сервере создался новый поток (или свободный из пула взят) и стал его выполнять. Клиент устал ждать и нажимает кнопку "Отменить". Сервер получает новый запрос "отменить" (очевидно, обрабатывается другим сервлетом). Опять создается новый поток, чтобы выполнить эту команду, т.е. остановить первый поток. Чтобы остановить выполнение первого потока надо предусмотреть в его шагах условия остановки, т.е. контрольную точку, флаг, которую он периодически проверяет, не слишком ли долго он копается с обработкой. Если да, то поток прекращает выполнение и закрывает соединение или шлет код ошибки. А второй поток, отменяющий, должен иметь доступ к этому флагу. Если бы клиент предполагался всегда один, то этот флаг можно было бы сделать статическим. Но если клиентов одновременно может быть много, то этот флаг должен быть в сессии клиента, чтобы клиент не отменил чужой запрос.

Да, речь о том, чтобы остановить поток. И поток будет один, т.к. мой сервлет-класс реализует SingleThreadModel интерфейс (правда он deprecated, но речь не об этом).

Souljah, если ты имеешь ввиду: не получится убрать <servlet> из web.xml, то я с этим согласен. Требуется просто остановить. Я точно не могу сформулировать свою задачу.

Просто скажу то, что к сервлету постоянно кто-то обращается и передаёт какую-то информацию. Я хочу с помощью запроса типа http://server:8080/MyServlet?action=shutdown остановить его. Что в данном случае остановить - не знаю. Возможно запустить его метод destroy, возможно ещё есть какие-то варианты?

Опять повторюсь : Забегая вперёд, хочу спросить, можно ли таким же образом осуществить запуск первого сервлета?

Спасибо за помощь.

Автор: olegrolik 3.12.2007, 11:02
Maksym, попробовал вариант с this.destroy(). Метод вроде бы выполняется, но сервлет не убивается, т.е. потом запросы к нему приходят. Ты был прав.
Вопрос остаётся открытым.

Автор: Maksym 3.12.2007, 12:24
1. Обрамить весь код в service() сервлета if'ом по какому-нибудь флагу из статики. Сделать синхронизированный метод по переключению этого флага (action=shutdown будет дергать это метод). При вызове сервлета клиентом -- service(), конечно, отработает но if его не пустит, а на else можно повесить, например, редирект на какую-нибудь страницу "сервис отключен, обратитесь к администрации".

2. Написать фильтр, который будет перехватывать обращения к сервлетам и проверять включена ли эта функциональность (вызванный сервлет) в данный момент. Если нет -- делать редирект на всю ту же "сервис отключен, обратитесь к администрации".

Оба подхода позволяют включить функциональность обратно (а вдруг понадобится..) без перезапуска контейнера.
Второй подход намного гибче и идеологически вернее -- рекомендую его.
Сама же идея принудительной выгрузки сервлета "изнутри" не кажется мне правильной в рамках лайф цикла веб-приложения; разработчики контейнера и спецификации тоже, думаю, не случайно не оставили такой возможности.


Автор: olegrolik 3.12.2007, 13:23
Maksym, совсем не понял что ты хотел сказать. Синхронизация мне не нужна, т.к. инстанс будет всегда один.
Код



public boolean WORKING = true;


public void service(HttpServletRequest req, HttpServletResponse res) {
        String actionStr = req.getParameter("act");
                if(actionStr.equals("shutdown")) WORKING = false;
    }



Цитата
При вызове сервлета клиентом -- service(), конечно, отработает но if его не пустит, а на else можно повесить, например, редирект

Это о чём вообще?
Цитата

2. Написать фильтр, который будет перехватывать обращения к сервлетам и проверять включена ли эта функциональность (вызванный сервлет) в данный момент.
 А фильтр этот тоже в методе service() ? Что он из себя представляет? Метод ?

Автор: Maksym 3.12.2007, 14:25
Цитата(olegrolik @  3.12.2007,  12:23 Найти цитируемый пост)
Это о чём вообще?

Может быть я очень сложно  написал очень простую мысль о том, что запретить выполнение кода в метода можно с помощью конструкции if.. сори  smile 

http://java.sun.com/products/servlet/Filters.html

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



Автор: olegrolik 3.12.2007, 17:18
Maksym, спасибо. С нетерпением жду твою версию.
Я тут сделал небольшой "трюк". Смысл моего приложения в приёме файла от клиента.
Я создал public class Global, который содержит в себе перменную boolean manage.

Код


public class Global {
    public static boolean manage = true;
}



В сервлете рассмотрел следующие условия (метод doGet, к примеру):
Код

if(Global.manage==true && req.getParameter("act").equals("shutdown")) { 
                Global.manage=false;
                System.out.println("Система остановлена.");
                
            }
if(Global.manage==false && req.getParameter("act").equals("on")) { 
            Global.manage=true;
            System.out.println("Система запущена.");
            // здесь мы обрабатываем файл, короче тут бизнес-логика.
        }
// Здесь код для оповещения клиента. Случай, когда мы не разрешаем ему работу
if(Global.manage==false && !req.getParameter("act").equals("on")) 
            try {
                res.sendRedirect("http://страница с ошибкой");
                System.out.println("ошибка, редирект на мэйл.ру.");
                System.out.println(Global.manage);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }


Как вам такой вариант? Конечно не "стильно", зато полностью отвечает тому, что я хотел сделать. Получается, что тему неправильно назвал. Хотя, посмотрим что предложит Maksym.

Автор: Maksym 3.12.2007, 17:31
olegrolik
В последнем примере ты положил флаг в статику, а изменяешь его из кода, который будет выполняться в различных потоках. Мне кажется, что здесь нужна синхронизация доступа к этому флагу.

Посмотрел ли ты про фильтры? Это инструмент специально предназначенный для осуществления проверок такого типа, как в последнем сервлете.

Автор: olegrolik 3.12.2007, 17:46
Maksym, у меня поток будет один, т.к. сервлет реализует SingleThreadModel интерфейс.
Фильтры посмотрел, но видимо здесь можно обойтись и без них. 
P.S. Я собираюсь реализовывать это дело в Spring MVC. Эти условия (if'ы) будут прописаны в контроллере. 


хмм.... если Spring, то прийдётся сделать синхронизацию доступа. Не хочется использовать просто устаревший интерфейс SingleThreadModel. К тому же под вопросом возможность его использования. 
Как бы то ни было, Maksym, спасибо. Лови плюсик!  smile 


Также хочу добавить, что клиент может сам остановить сервлет. А это недопустимо. В принципе можно в качестве параметра взять что-то вроде: "45345fdsfisdof3i-3ffsdf"  smile 
Но это некрасиво. 

Кто ещё что предложит?

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)