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 .