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

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

Неблокирующий ввод/вывод

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

Например, если клиент отправляет большой HTTP запрос POST по медленному сетевому соединению, сервер может прочитать запрос быстрее, чем клиент может его предоставить. При использовании традиционного ввода-вывода поток контейнера, связанный с этим запросом, иногда будет простаивать в ожидании оставшейся части запроса.

Java EE обеспечивает неблокирующую поддержку ввода-вывода для сервлетов и фильтров при обработке запросов в асинхронном режиме. Следующие шаги описывают, как использовать неблокирующий ввод-вывод для обработки запросов и записи ответов внутри сервисных методов.

  1. Переведите запрос в асинхронный режим, как описано в Асинхронная обработка.

  2. Получите входной поток и/или выходной поток из объектов запроса и ответа в сервисном методе.

  3. Назначьте слушатель чтения входному потоку и/или слушатель записи выходному потоку.

  4. Обработайте запрос и ответ внутри Callback-методов слушателя.

Таблица 18-4 и таблица 18-5 описывают методы, доступные во входных и выходных потоках сервлета для поддержки неблокирующего ввода/вывода. Таблица 18-6 описывает интерфейсы для слушателей чтения и записи.

Таблица 18-4. Поддержка неблокирующего ввода-вывода в javax.servlet.ServletInputStream

Метод

Описание

void setReadListener(ReadListener rl)

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

boolean isReady()

Возвращает true, если данные могут быть прочитаны без блокировки.

boolean isFinished()

Возвращает true, когда все данные были прочитаны.

Таблица 18-5. Поддержка неблокирующего ввода-вывода в javax.servlet.ServletOutputStream

Метод

Описание

void setWriteListener(WriteListener wl)

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

boolean isReady()

Возвращает true, если данные могут быть записаны без блокировки.

Таблица 18-6 Интерфейсы слушателей для поддержки неблокирующего ввода-вывода

Интерфейс

Методы

Описание

ReadListener

void onDataAvailable()

void onAllDataRead()

void onError(Throwable t)

Объект ServletInputStream вызывает эти методы на своём слушателе, когда есть данные, доступные для чтения, когда все данные прочитаны или когда есть ошибка.

WriteListener

void onWritePossible()

void onError(Throwable t)

Объект ServletOutputStream вызывает эти методы на своём слушателе, когда возможно записать данные без блокировки или когда есть ошибка.

Чтение большого HTTP POST-запроса с использованием неблокирующего ввода/вывода

Код в этом разделе показывает, как прочитать большой HTTP POST-запрос внутри сервлета, переведя запрос в асинхронный режим (как описано в Асинхронная обработка) и используя функцию неблокирующего ввода-вывода из таблицы 18-4 и таблицы 18-6.

@WebServlet(urlPatterns={"/asyncioservlet"}, asyncSupported=true)
public class AsyncIOServlet extends HttpServlet {
   @Override
   public void doPost(HttpServletRequest request,
                      HttpServletResponse response)
                      throws IOException {
      final AsyncContext acontext = request.startAsync();
      final ServletInputStream input = request.getInputStream();

      input.setReadListener(new ReadListener() {
         byte buffer[] = new byte[4*1024];
         StringBuilder sbuilder = new StringBuilder();
         @Override
         public void onDataAvailable() {
            try {
               do {
                  int length = input.read(buffer);
                  sbuilder.append(new String(buffer, 0, length));
               } while(input.isReady());
            } catch (IOException ex) { ... }
         }
         @Override
         public void onAllDataRead() {
            try {
               acontext.getResponse().getWriter()
                                     .write("...the response...");
            } catch (IOException ex) { ... }
            acontext.complete();
         }
         @Override
         public void onError(Throwable t) { ... }
      });
   }
}

В этом примере объявляется веб-сервлет с асинхронной поддержкой с использованием параметра аннотации @WebServlet asyncSupported=true. Сервисный метод сначала переводит запрос в асинхронный режим, вызывая метод startAsync() объекта запроса, который необходим для использования неблокирующего ввода-вывода. Затем сервисный метод получает входной поток, связанный с запросом, и назначает слушатель чтения, определённый как внутренний класс. Слушатель читает части запроса, когда они становятся доступными, и затем записывает некоторый ответ клиенту, когда он заканчивает чтение запроса.


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