Сервлеты Servlets

Servlet - это java-программа, которая выполняется на серверной стороне Web-приложения. Точно так же, как апплеты динамически расширяют функциональные возможности Web-браузера, сервлеты динамически расширяют функциональные возможности Web-сервера.

Работу servlet'а можно описать следующим образом: при приходе запроса от клиента Web-сервер с помощью специального конфигурационного файла может определить, какой сервлет необходимо выполнить. После этого Web-сервер запускает JVM, которая в свою очередь выполняет сервлет. Servlet обрабатывает запрос и передает содержимое Web-серверу (возможно в виде HTML-страницы). Web-сервер отправляет клиенту ответ (сформированную сервлетом HTML-страницу).

WEB-сервер по сути является неким контейнером, который загружает servlet'ы, выполняет их, и, получив от них результат, отправляет его клиенту.

Servlet в архитектуре Web-приложения

Из-за своей мощности и гибкости, servlet'ы могут играть значительную роль в архитектуре системы. Они могут выполнять прикладные задачи, предназначенные для промежуточного уровня, работать как прокси-сервер для клиента и даже улучшать функциональность промежуточного уровня, добавляя поддержку новых протоколов и других функций. Промежуточный уровень выполняет функции сервера приложений в так называемой трехуровневой системе клиент-сервер и расположен между "легковесным" клиентом, таким как Web-браузер, и источником данных.

Servlet как прокси-сервер

Для поддержки апплетов сервлеты могут выполнять функции их прокси-серверов. Это может быть важно, поскольку система безопасности Java позволяет апплетам соединяться только с сервером, с которого они были загружены. Если апплет нуждается в соединении с сервером баз данных, расположенном на другой машине, servlet может создать это соединение для апплета.

Временные и постоянные servlet

Сервлеты могут запускаться и останавливаться для каждого клиентского запроса. Также они могут запускаться при старте Web-сервера и существовать до его остановки. Временные servlet'ы загружаются по требованию и предлагают хороший способ сохранения ресурсов сервера для редко используемых функций. Постоянные сервлеты загружаются при старте Web-сервера и существуют до его остановки. Сервлеты устанавливаются как постоянные расширения для сервера в том случае, если затраты по их запуску очень велики (например, установка соединения с базой данных), если они предлагают постоянную функциональность на стороне сервера (например, служба RMI), или в случаях, когда они должны отвечать на запросы клиента как можно быстрее. Не существует специального кода для назначения servlet'а постоянным или временным; это функция настройки Web-сервера.

Жизненный цикл сервлета, javax.servlet.Servlet

Сервлеты выполняются на платформе Web-сервера как часть того же процесса, что и сам Web-сервер. Web-сервер отвечает за инициализацию, вызов и уничтожение каждого экземпляра сервлета. Web-сервер взаимодействует с сервлетом через простой интерфейс: javax.servlet.Servlet.

Интерфейс javax.servlet.Servlet включает три главных методов:

  • init()
  • service()
  • destroy()

и два вспомогательных методов:

  • getServletConfig()
  • getServletInfo()

Сходство между интерфейсами servlet'а и апплета Java очевидны. Именно так и было спроектировано! Java сервлеты являются для Web-серверов тем же самым, чем являются апплеты для Web-браузеров. Апплет выполняется в Web-браузере, выполняя действия по его запросу через специальный интерфейс. Сервлет делает то же самое, работая на Web-сервере.

Инициализация сервлета, метод init()

При первой загрузке сервлета вызывается метод init(). Это дает возможность сервлету выполнить любую работу по установке, например, открытие файлов или установку соединений с их серверами. Если сервлет установлен на сервере постоянно, он загружается при запуске сервера. В противном случае сервер активизирует сервлет при получении первого запроса от клиента на выполнение услуги, обеспечиваемой этим сервлетом.

Гарантируется, что метод init() закончится перед любым другим обращением к сервлету – таким как, например, вызов метода service(). Обратите внимание, что init() будет вызван только один раз; он не будет вызываться до тех пор, пока сервлет не будет выгружен и затем загружен сервером снова.

Метод init() принимает один аргумент – ссылку на объект ServletConfig, который содержит аргументы для инициализации сервлета. Этот объект имеет метод getServletContext(), возвращающий объект ServletContext, который содержит информацию об окружении сервлета.

Ядро сервлета, метод service()

Метод service() является сердцем сервлета. Каждый запрос от клиента приводит к одному вызову метода service(). Этот метод читает запрос и формирует ответное сообщение при помощи своих двух аргументов ServletRequest и ServletResponse :

  • Объект ServletRequest содержит данные от клиента. Данные состоят из пар имя/значение и InputStream. Существует несколько методов, возвращающих информацию о параметрах клиента. InputStream может быть получен при помощи метода getInputStream(). Этот метод возвращает объект ServletInputStream, который можно использовать для получения дополнительных данных от клиента. Если необходима выполнить обработку символьных данных, а не двоичных, то можно получить объект BufferedReader при помощи метода getReader().
  • Объект ServletResponse содержит ответ сервлета клиенту. Во время подготовки ответа прежде всего вызывается метод setContentType() для установки типа MIME ответа. Затем могут быть использованы методы getOutputStream() или getWriter() для получения объектов и ServletOutputStream или PrintWriter соответственно для передачи данных обратно клиенту.

Таким образом, существуют два способа передачи информации от клиента к сервлету. Первый – через передачу значений в параметрах запроса. Значения параметров могут быть вставлены в URL. Второй способ передачи информации от клиента к сервлету осуществляется через InputStream (или Reader).

Работа метода service() по существу проста – он создает ответ на каждый клиентский запрос, переданный ему с сервера. Однако необходимо помнить, что могут существовать несколько параллельных запросов, обрабатываемых в одно и то же время. Если метод service() требует каких-либо внешних ресурсов, таких как файлы, базы данных, то необходимо гарантировать, чтобы доступ к ресурсам являлся потокозащищенным.

Выгрузка сервлета, метод destroy()

Метод destroy() вызывается для освобождения всех ресурсов (например, открытые файлы и соединения с базой данных) перед выгрузкой сервлета. Этот метод может быть пустым, если нет необходимости выполнения каких-либо завершающих операций. Перед вызовом метода destroy() сервер ждет либо завершения всех обслуживающих операций, либо истечения определенного времени. Это означает, что метод destroy() может быть вызван во время выполнения какого-либо продолжительного метода service().

Важно оформить метод destroy() таким образом, чтобы избежать закрытия необходимых ресурсов до тех пор, пока все вызовы service() не завершатся.

Конфигурация сервлета, метод getServletConfig()

Метод getServletConfig() возвращает ссылку на объект, который реализует интерфейс ServletConfig. Данный объект предоставляет доступ к информации о конфигурации сервлета, т.е. доступ к параметрам инициализации сервлета и объекту контектса сервлета ServletContext, который дает доступ к сервлету и его окружению.

Информация о сервлете, метод getServletInfo()

Метод getServletInfo() определяется программистом, создающим сервлет, для возврата строки, содержащую информацию о сервлете, например: автор и версия сервлета.

Интерфейс ServletRequest

ServletRequest предоставляет клиентскую информацию о параметрах HTTP запроса сервлету, т.е. обеспечивает данные включая название параметра и значения, атрибуты, и входной поток. Эта информация передается в метод service().

Следующий servlet пример показывает, как получить информацию из параметра request метода service():

BufferedReader reader;  
String         param1;  
String         param2;  
  
public void service(ServletRequest request, ServletResponse response) 
{  
    reader = request.getReader();  
    param1 = request.getParameter("First");  
    param2 = request.getParameter("Second");  
}  

Дополнительная информация о запросе доступна сервлету через методы, основные из которых приведены в следующей таблице:

getAttribute () Возвращает значение указанного атрибута этого запроса.
getContentLength () Размер запроса, если известен.
getContentType () Возвращает тип MIME тела запроса.
getInputStream () Возвращает InputStream для чтения двоичных данных из тела запроса.
GetParameterNames () Возвращает массив строк с именами всех параметров.
getParameterValues () Возвращает массив значений для указанного параметра.
getProtocol () Возвращает протокол и версию для запроса как строку вида <protocol>/<major version>.<minor version>.
getReader () Возвращает BufferedReader для получения текста из тела запроса.
getRealPath () Возвращает реальный путь для указанного виртуального пути.
getRemoteAddr () IP-адрес клиента, пославшего данный запрос.
getRemoteHost () Имя хоста клиентской машины, пославшего данный запрос.
getScheme () Возвращает схему, используемую в URL этого запроса (например, https, http, ftp, и т.д.).
getServerName () Имя хоста сервера, принявшего данный запрос.
getServerPort () Возвращает номер порта, используемого для приема этого запроса.

Интерфейс ServletResponse

Интерфейс ServletResponse - это инструмент для отправки данных клиенту. Все методы данного инструмента служат именно для решения этой задачи :

public java.lang.String getCharacterEncoding()
public void setLocale(java.util.Locale loc)
public java.util.Locale getLocale()

Первый метод возвращает MIME тип кодировки (к примеру - UTF8), в которой будет выдаваться информация. Вторые два метода тоже работают с charset. Они указывают на язык используемый в документе (например - русский).

public ServletOutputStream getOutputStream() throws java.io.IOException

Метод getOutputStream возвращает поток вывода данных для сервлета. Этот поток используется, к примеру, для вывода бинарных файлов. Текстовые данные можно выводить с помощью java.io.Writer:

public java.io.PrintWriter getWriter() throws java.io.IOException

Метод getWriter() автоматически конвертирует строки в тот charset, что указан в методе getCharacterEncoding() и getLocale().

public void setContentLength(int len)

Методом setContentLength устанавливается значение поля HTTP заголовка "Content-Length"

public void setContentType(String type)

Метод setContentType используется для отправки MIME типа содержимого документа. Поле HTTP заголовка "Content-Type".

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

public void setBufferSize(int size)
public int getBufferSize()
public void flushBuffer() throws java.io.IOException
public void resetBuffer()

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

public boolean isCommitted()

Методом isCommitted можно получить флаг, начата ли уже отправка данных клиенту. Флаг будет положительным, если HTTP заголовок ответа был уже отправлен.

public void reset()

Если HTTP заголовок ещё не отправлен, то метод reset "сбрасывает" HTTP заголовок к значениям "по умолчанию".

  Рейтинг@Mail.ru