Перейти к основному содержимому

Введение в сервлеты и контейнеры сервлетов

· 5 мин. чтения

1. Обзор

В этом руководстве мы концептуально поймем, что такое сервлеты и контейнеры сервлетов и как они работают .

Мы также увидим их в контексте запроса, ответа, объектов сеанса, общих переменных и многопоточности.

2. Что такое сервлеты и их контейнеры

Сервлеты — это компонент среды JEE, используемый для веб-разработки. По сути, это Java-программы, работающие внутри границ контейнера. В целом они отвечают за прием запроса, его обработку и отправку ответа . Введение в сервлеты Java обеспечивает хорошее базовое понимание предмета.

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

После завершения инициализации сервлет готов принимать входящие запросы. Впоследствии контейнер направляет эти запросы на обработку в методе service() сервлета. После этого он далее делегирует запрос соответствующему методу, такому как doGet() или doPost() , в зависимости от типа HTTP-запроса.

С помощью destroy() контейнер разрывает сервлет и больше не может принимать входящие запросы. Мы называем этот цикл init-service-destroy жизненным циклом сервлета .

Теперь давайте посмотрим на это с точки зрения контейнера, такого как Apache Tomcat или Jetty . При запуске он создает объект ServletContext . Задача ServletContext состоит в том, чтобы функционировать как память сервера или контейнера и запоминать все сервлеты, фильтры и прослушиватели, связанные с веб-приложением, как описано в его web.xml или эквивалентных аннотациях. Пока мы не остановим или не завершим контейнер, ServletContext останется с ним.

Однако параметр загрузки при запуске сервлета играет здесь важную роль `` . Если этот параметр имеет значение больше нуля, только тогда сервер инициализирует его при запуске. Если этот параметр не указан, то функция init() сервлета вызывается при первом запросе.

3. Запрос, ответ и сеанс

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

В этом случае запрос будет представлен HttpServletRequest , а ответ — HttpServletResponse .

Всякий раз, когда клиент, такой как браузер или команда curl, отправляет запрос, контейнер создает новый объект HttpServletRequest и HttpServletResponse . Затем он передает эти новые объекты сервисному методу сервлета. На основе атрибута метода HttpServletRequest этот метод определяет, какой из методов doXXX следует вызывать.

Помимо информации о методе, объект запроса также содержит другую информацию, такую как заголовки, параметры и тело. Точно так же объект HttpServletResponse также содержит заголовки, параметры и тело — мы можем настроить их в методе doXXX нашего сервлета .

Эти объекты недолговечны . Когда клиент получает ответ, сервер помечает объекты запроса и ответа для сборки мусора.

Как бы мы тогда поддерживали состояние между последующими клиентскими запросами или подключениями? HttpSession — ответ на эту загадку.

Это в основном привязывает объекты к сеансу пользователя, так что информация, относящаяся к конкретному пользователю, может сохраняться в нескольких запросах. Обычно это достигается с помощью концепции файлов cookie с использованием JSESSIONID в качестве уникального идентификатора для данного сеанса. Мы можем указать время ожидания сеанса в web.xml :

<session-config>
<session-timeout>10</session-timeout>
</session-config>

Это означает, что если наша сессия бездействовала в течение 10 минут, сервер отбросит ее. Любой последующий запрос создаст новый сеанс.

4. Как сервлеты обмениваются данными

Существуют различные способы обмена данными между сервлетами в зависимости от требуемой области.

Как мы видели в предыдущих разделах, разные объекты имеют разное время жизни. Объекты HttpServletRequest и HttpServletResponse существуют только между одним вызовом сервлета. HttpSession существует, пока он активен и не истекло время ожидания.

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

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

Наконец, есть область запроса, относящаяся к данным для одного запроса, например полезная нагрузка запроса.

5. Работа с многопоточностью

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

Что это фактически означает с точки зрения потокобезопасности, так это то, что мы не должны назначать данные области запроса или сеанса в качестве переменной экземпляра сервлета .

Например, рассмотрим этот фрагмент:

public class ExampleThree extends HttpServlet {

private String instanceMessage;

@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String message = request.getParameter("message");
instanceMessage = request.getParameter("message");
request.setAttribute("text", message);
request.setAttribute("unsafeText", instanceMessage);
request.getRequestDispatcher("/jsp/ExampleThree.jsp").forward(request, response);
}
}

В этом случае все запросы в сеансе совместно используют instanceMessage , тогда как сообщение уникально для данного объекта запроса. Следовательно, в случае одновременных запросов данные в instanceMessage могут быть несогласованными.

6. Заключение

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

Как всегда, исходный код доступен на GitHub .