Как работают сервлеты? Инстанциация, сессии, общие переменные и многопоточность

Методы расширения - это только статические методы. Единственное отличие заключается в таких инструментах, как редактор Visual Studio, который выставляет их для функции автоматического завершения (intellisense). Вы можете найти подробное объяснение здесь: C # Методы расширения: синтаксический сахар или полезный инструмент?

1081
задан Taryn 22 March 2017 в 16:22
поделиться

3 ответа

ServletContext

Когда запускается контейнер сервлетов (например, Apache Tomcat), он развертывает и загружает все свои веб-приложения. Когда веб-приложение загружено, контейнер сервлетов создает ServletContext один раз и сохраняет его в памяти сервера. web.xml веб-приложения и все включенные web-fragment. xml, и каждый <сервлет>, <фильтр> и <слушатель> найден (или каждый класс, аннотированный @WebServlet, @WebFilter и @WebListener соответственно) инстанцируется один раз и также хранится в памяти сервера. Для каждого инстанцированного фильтра вызывается его метод init() с новым FilterConfig.

Когда сервлет имеет или @WebServlet(loadOnStartup) значение больше 0, то его init() метод также вызывается во время запуска с новым ServletConfig. Эти сервлеты инициализируются в том же порядке, который указан этим значением (1 - первый, 2 - второй и т.д.). Если одно и то же значение указано для более чем одного сервлета, то каждый из этих сервлетов загружается в том же порядке, в каком они появляются в web.xml, web-fragment.xml или @WebServlet classloading. Если значение "load-on-startup" отсутствует, метод init() будет вызываться каждый раз, когда HTTP-запрос впервые попадает на этот сервлет.

Когда контейнер сервлетов закончит все описанные выше шаги инициализации, будет вызван ServletContextListener#contextInitialized() метод.

Когда контейнер сервлетов выключается, он выгружает все веб-приложения, вызывает метод destroy() всех своих инициализированных сервлетов и фильтров, и все ServletContext, Servlet, Filter и Listener экземпляры уничтожаются. Наконец, будет вызван ServletContextListener#contextDestroyed() .

HttpServletRequest и HttpServletResponse

Контейнер сервлетов подключен к веб-серверу, который прослушивает HTTP-запросы на определенном номере порта (обычно используется порт 8080 во время разработки и порт 80 в производстве). Когда клиент (например, пользователь с помощью веб-браузера или программно с помощью URLConnection) отправляет HTTP-запрос, контейнер сервлетов создает новые объекты HttpServletRequest и HttpServletResponse и пропускает их через любой определенный Filter в цепочке и, в конечном итоге, через экземпляр Servlet.

В случае фильтров вызывается метод doFilter(). Когда код контейнера сервлетов вызывает chain.doFilter(request, response), запрос и ответ переходят к следующему фильтру, или поражают сервлет, если не осталось ни одного фильтра.

В случае сервлетов вызывается метод service(). По умолчанию этот метод определяет, какой из методов doXxx() вызвать на основе request.getMethod(). Если определенный метод отсутствует в сервлете, то в ответ возвращается ошибка HTTP 405.

Объект request предоставляет доступ ко всей информации о HTTP-запросе, такой как его URL, заголовки, строка запроса и тело. Объект response предоставляет возможность контролировать и отправлять HTTP-ответ так, как вы хотите, например, позволяя вам устанавливать заголовки и тело (обычно сгенерированное HTML-содержимое из JSP-файла). Когда HTTP-ответ зафиксирован и завершен, объекты запроса и ответа перерабатываются и становятся доступными для повторного использования.

HttpSession

Когда клиент впервые посещает webapp и/или HttpSession впервые получен через request. getSession(), контейнер сервлетов создает новый объект HttpSession, генерирует длинный и уникальный ID (который можно получить по session.getId()) и сохраняет его в памяти сервера. Контейнер сервлетов также устанавливает Cookie в заголовке Set-Cookie HTTP-ответа с JSESSIONID в качестве имени и уникальным идентификатором сессии в качестве значения.

Согласно спецификации HTTP cookie (договор, которого должны придерживаться любой приличный веб-браузер и веб-сервер), клиент (веб-браузер) должен отправлять этот cookie обратно при последующих запросах в заголовке Cookie до тех пор, пока cookie действителен (т.е. уникальный ID должен относиться к неистекшей сессии, а домен и путь должны быть правильными). Используя встроенный в браузер монитор HTTP-трафика, вы можете убедиться, что cookie действителен (нажмите F12 в Chrome / Firefox 23+ / IE9+ и проверьте вкладку Net/Network). Контейнер сервлетов будет проверять заголовок Cookie каждого входящего HTTP-запроса на наличие cookie с именем JSESSIONID и использовать его значение (идентификатор сессии) для получения связанной с ним HttpSession из памяти сервера.

Сессия HttpSession остается живой до тех пор, пока она не будет простаивать (т.е. не будет использоваться в запросе) дольше, чем значение таймаута, указанное в , параметре в web.xml. Значение тайм-аута по умолчанию равно 30 минутам. Поэтому, когда клиент не посещает веб-приложение дольше указанного времени, контейнер сервлетов уничтожает сессию. Каждый последующий запрос, даже с указанным cookie, больше не будет иметь доступа к той же сессии; контейнер сервлетов создаст новую сессию.

На стороне клиента файл cookie сессии остается живым до тех пор, пока работает экземпляр браузера. Поэтому, если клиент закрывает экземпляр браузера (все вкладки/окна), то сессия на стороне клиента уничтожается. В новом экземпляре браузера cookie, связанный с сессией, не будет существовать, поэтому он больше не будет отправлен. Это приводит к созданию совершенно новой HttpSession, с использованием совершенно новой куки сессии.

В двух словах

  • ServletContext живет до тех пор, пока живет веб-приложение. Он разделяется между всеми запросами в всех сессиях.
  • Сессия HttpSession живет до тех пор, пока клиент взаимодействует с веб-приложением с помощью одного и того же экземпляра браузера, и сессия не завершилась на стороне сервера. Она разделяется между всеми запросами в одной сессии.
  • Сервлеты HttpServletRequest и HttpServletResponse живут с момента получения сервлетом HTTP-запроса от клиента до получения полного ответа (веб-страницы). Он не разделяется в других местах.
  • Все экземпляры сервлета, фильтра и слушателя живут до тех пор, пока живет веб-приложение. Они разделяются между всеми запросами в всех сессиях.
  • Любой атрибут, определенный в ServletContext, HttpServletRequest и HttpSession, будет жить до тех пор, пока живет данный объект. Сам объект представляет собой "область видимости" во фреймворках управления бобами, таких как JSF, CDI, Spring и т.д.. Эти фреймворки хранят свои scoped beans как атрибут ближайшего подходящего scope.

Безопасность потоков

Учитывая это, ваша основная проблема, возможно, заключается в безопасности потоков. Теперь вы должны знать, что сервлеты и фильтры разделяются между всеми запросами. Это хорошая вещь в Java, она многопоточна, и разные потоки (читай: HTTP-запросы) могут использовать один и тот же экземпляр. Иначе было бы слишком дорого воссоздавать, инициировать() и уничтожать() их для каждого отдельного запроса.

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

public class ExampleServlet extends HttpServlet {

    private Object thisIsNOTThreadSafe;

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        Object thisIsThreadSafe;

        thisIsNOTThreadSafe = request.getParameter("foo"); // BAD!! Shared among all requests!
        thisIsThreadSafe = request.getParameter("foo"); // OK, this is thread safe.
    } 
}

См. также:

1779
ответ дан 19 December 2019 в 20:19
поделиться

Sessions - то, что сказал Крис Томпсон.

Instantiation - сервлет инстанцируется, когда контейнер получает первый запрос, сопоставленный с сервлетом (если только сервлет не настроен на загрузку при запуске с помощью элемента в web.xml). Этот же экземпляр используется для обслуживания последующих запросов.

20
ответ дан 19 December 2019 в 20:19
поделиться

Сессия в сервлетах Java - это то же самое, что и сессия в других языках, таких как PHP. Она уникальна для пользователя. Сервер может отслеживать его различными способами, такими как cookies, переписывание url и т.д. Эта Java doc статья объясняет это в контексте сервлетов Java и указывает, что то, как именно поддерживается сессия, является деталью реализации, оставленной на усмотрение разработчиков сервера. В спецификации только указано, что он должен сохраняться уникальным для пользователя при нескольких соединениях с сервером. Посмотрите эту статью от Oracle для получения дополнительной информации по обоим вашим вопросам.

Редактировать Есть отличный учебник здесь о том, как работать с сессией внутри сервлетов. А здесь - глава от Sun о Java Servlets, что это такое и как их использовать. Между этими двумя статьями вы сможете ответить на все свои вопросы.

42
ответ дан 19 December 2019 в 20:19
поделиться
Другие вопросы по тегам:

Похожие вопросы: