Java Platform, Enterprise Edition (Java EE) 8
Учебник по Java EE

Назад Вперёд Содержание

Финализация сервлета

Веб-контейнер может определить, что сервлет должен быть удалён (например, когда контейнер хочет освободить память или когда он выключен). В таком случае контейнер вызывает метод destroy интерфейса Servlet. В этом методе вы освобождаете любые ресурсы, которые использует сервлет, и сохраняете любое персистентное состояние. Метод destroy освобождает объект базы данных, созданный в методе init.

Все сервисные методы сервлета должны быть завершены при удалении сервлета. Сервер пытается убедиться в этом, вызывая метод destroy только после того, как все запросы на обслуживание выполнены или по истечении заданного времени (grace period), в зависимости от того, что наступит раньше. Если в вашем сервлете есть операции, которые могут выполняться дольше, чем специальный период сервера (grace period), эти операции могут выполняться при вызове destroy. Вы должны убедиться, что все потоки, по-прежнему обрабатывающие клиентские запросы, завершены.

В оставшейся части этого раздела объясняется, как это сделать.

  • Отслеживайте, сколько потоков в настоящее время выполняет метод service.

  • Обеспечьте чистое завершение работы с помощью метода destroy, чтобы уведомить долго выполняющиеся потоки о завершении работы и дождаться их завершения.

  • Периодически опрашивайте долго выполняющиеся методы для проверки завершения их работы и, при необходимости, их прекращение, очистку и возврат результатов.

Сервис отслеживания запросов

Для отслеживания запросов на обслуживание:

  1. Включите в класс сервлета поле, которое подсчитывает количество запущенных сервисных методов.

    Поле должно иметь синхронизированные методы доступа для увеличения, уменьшения и возврата значения:

    public class ShutdownExample extends HttpServlet {
        private int serviceCounter = 0;
        ...
        // Методы доступа serviceCounter
        protected synchronized void enteringServiceMethod() {
            serviceCounter++;
        }
        protected synchronized void leavingServiceMethod() {
            serviceCounter--;
        }
        protected synchronized int numServices() {
            return serviceCounter;
        }
    }

    Метод service должен увеличивать сервисный счётчик каждый раз, когда выполняется вход в метод, и должен уменьшать счётчик каждый раз, когда выполняется выход из метода. Это один из немногих случаев, когда ваш дочерний класс HttpServlet должен переопределять метод service. Новый метод должен вызывать super.service для сохранения функциональности исходного метода service:

    protected void service(HttpServletRequest req,
                           HttpServletResponse resp)
                           throws ServletException,IOException {
        enteringServiceMethod();
        try {
            super.service(req, resp);
        } finally {
            leavingServiceMethod();
        }
    }

Уведомление методов о выключении

Чтобы обеспечить полное выключение, ваш метод destroy не должен освобождать какие-либо общие ресурсы, пока не будут завершены все запросы на обслуживание:

  1. Проверьте сервисный счётчик.

  2. Уведомите долго выполняющиеся методы о том, что пора завершать работу.

    Для этого уведомления требуется другое поле. Поле должно иметь обычные методы доступа:

    public class ShutdownExample extends HttpServlet {
        private boolean shuttingDown;
        ...
        // Методы доступа shuttingDown
        protected synchronized void setShuttingDown(boolean flag) {
            shuttingDown = flag;
        }
        protected synchronized boolean isShuttingDown() {
            return shuttingDown;
        }
    }

    Вот пример метода destroy, использующего эти поля для обеспечения корректного завершения работы:

    public void destroy() {
        /* Проверка, есть ли ещё работающие сервисные методы, /*
        /* и если они есть, их остановка. */
        if (numServices()> 0) {
            setShuttingDown(true);
        }
    
        /* Ожидание остановки сервисного метода. */
        while (numServices()> 0) {
            try {
                Thread.sleep(interval);
            } catch (InterruptedException e) {
            }
        }
    }

Корректное создание долго выполняющихся методов

Последний шаг в обеспечении чистого завершения работы — заставить все долго выполняющиеся методы вести себя корректно. Долго выполняющиеся методы должны проверять значение поля, которое уведомляет их о выключении, и они должны прервать свою работу, если необходимо:

public void doPost(...) {
    ...
    for(i = 0; ((i < lotsOfStuffToDo) &&
         !isShuttingDown()); i++) {
        try {
            partOfLongRunningOperation(i);
        } catch (InterruptedException e) {
            ...
        }
    }
}

Назад Вперёд Содержание
Логотип Oracle  Copyright © 2017, Oracle и/или её дочерних компаний. Все права защищены. Версия перевода 1.0.5 (Java EE Tutorial — русскоязычная версия)