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

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

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

Еще один похожий вопрос, если есть n если пользователи получают доступ к определенному сервлету, то этот сервлет создается только при первом обращении к нему первого пользователя, или он создается для всех пользователей отдельно? Другими словами, что происходит с переменными экземпляра?

8 ответов

Решение

ServletContext

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

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

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

HttpServletRequest и HttpServletResponse

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

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

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

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

HttpSession

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

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

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

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

В двух словах

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

Поток безопасности

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

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

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.
    } 
}

Смотрите также:

сессии

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

Сервлет Инстанция

Если загрузка при запуске имеет значение false:

Если загрузка при запуске - это правда:

Как только он перейдет в сервисный режим и в паз, тот же сервлет будет работать с запросами всех других клиентов.

Почему не стоит иметь один экземпляр на клиента? Подумайте об этом: вы будете нанимать по одному парню пиццы на каждый заказ? Сделайте это, и вы будете вне бизнеса в кратчайшие сроки.

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

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

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

Когда сервлет-контейнер (например, Apache Tomcat) запускается, он будет читать из файла web.xml (только один на приложение), если что-то пойдет не так или обнаружит ошибку на консоли на стороне контейнера, в противном случае он развернет и загрузит весь веб приложения с помощью web.xml (так называемый дескриптор развертывания).

На этапе создания экземпляра сервлета экземпляр сервлета готов, но он не может обслуживать клиентский запрос, поскольку отсутствует две части информации:
1: контекстная информация
2: информация о начальной конфигурации

Механизм сервлета создает интерфейсный объект servletConfig, инкапсулируя в него недостающую информацию, описанную выше. Механизм сервлета вызывает init() сервлета, предоставляя ссылки на объект servletConfig в качестве аргумента. Как только init() полностью выполнен, сервлет готов обслуживать запрос клиента.

Q) Сколько раз в жизни сервлета происходит инициализация и инициализация??

A) только один раз (для каждого клиентского запроса создается новый поток) только один экземпляр сервлета обслуживает любое количество клиентских запросов, т. Е. После обслуживания один клиентский сервер запросов не умирает. Он ожидает других клиентских запросов, то есть какой CGI (для каждого клиентского запроса создается новый процесс) ограничение преодолевается с помощью сервлета (внутренний механизм сервлета создает поток).

Q) Как работает концепция сессии?

А) всякий раз, когда getSession() вызывается для объекта HttpServletRequest

Шаг 1: объект запроса оценивается для входящего идентификатора сеанса.

Шаг 2: если идентификатор недоступен, создается новый объект HttpSession и генерируется соответствующий ему идентификатор сеанса (т. Е. HashTable). Идентификатор сеанса сохраняется в объекте ответа httpservlet, а ссылка на объект HttpSession возвращается сервлету (doGet / doPost).,

Шаг 3: если идентификатор доступен, новый объект сеанса не создан. Идентификатор сеанса выбирается из запроса. Поиск объекта производится в коллекции сеансов с использованием идентификатора сеанса в качестве ключа.

После успешного поиска идентификатор сеанса сохраняется в HttpServletResponse, а ссылки на существующие объекты сеанса возвращаются в doGet () или doPost () UserDefineservlet.

Замечания:

1) когда управление уходит от кода сервлета к клиенту, не забывайте, что объект сеанса удерживается контейнером сервлета, т. Е. Механизмом сервлета

2) многопоточность оставлена ​​разработчикам сервлетов для реализации, т. Е. Обрабатывать множественные запросы клиента, не беспокоясь о многопоточном коде

Краткая форма:

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

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

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

Спецификация сервлета JSR-315 четко определяет поведение веб-контейнера в методах службы (и doGet, doPost, doPut и т. Д.) (2.3.3.1 Проблемы многопоточности, Страница 9):

Контейнер сервлета может отправлять параллельные запросы через сервисный метод сервлета. Для обработки запросов разработчик сервлета должен предусмотреть адекватные условия для одновременной обработки с несколькими потоками в методе обслуживания.

Хотя это и не рекомендуется, альтернативой для разработчика является реализация интерфейса SingleThreadModel, который требует, чтобы контейнер гарантировал, что в методе службы одновременно присутствует только один поток запросов. Контейнер сервлета может удовлетворить это требование путем сериализации запросов к сервлету или путем поддержки пула экземпляров сервлета. Если сервлет является частью веб-приложения, которое было помечено как распространяемое, контейнер может поддерживать пул экземпляров сервлета в каждой JVM, по которой распространяется приложение.

Для сервлетов, не реализующих интерфейс SingleThreadModel, если метод службы (или такие методы, как doGet или doPost, которые отправляются методу службы абстрактного класса HttpServlet) был определен с ключевым словом synchronized, контейнер сервлета не может использовать подход пула экземпляров, но должен сериализовать запросы через него. Настоятельно рекомендуется, чтобы разработчики не синхронизировали метод обслуживания (или методы, отправленные ему) в этих обстоятельствах из-за отрицательного влияния на производительность.

Как ясно из приведенных выше объяснений, с помощью реализации SingleThreadModel сервлет может гарантировать безопасность потока с помощью контейнера сервлета. Реализация контейнера может сделать это двумя способами:

1) Сериализация запросов (постановка в очередь) для одного экземпляра - это похоже на сервлет, НЕ реализующий SingleThreadModel, НО синхронизирующий методы service/ doXXX; ИЛИ ЖЕ

2) Создание пула экземпляров - что является лучшим вариантом и компромисс между загрузкой / инициализацией / временем сервлета по сравнению с ограничительными параметрами (память / время ЦП) среды, в которой размещен сервлет.

Нет. Сервлеты не безопасны

Это позволяет получить доступ к более чем одному потоку одновременно

если вы хотите сделать его Servlet как потокобезопасным., вы можете пойти на

Implement SingleThreadInterface(i) который является пустым интерфейсом нет

методы

или мы можем пойти на методы синхронизации

мы можем сделать весь метод обслуживания как синхронизированный, используя синхронизированный

Keword перед методом

Пример::

public Synchronized class service(ServletRequest request,ServletResponse response)throws ServletException,IOException

или мы можем положить блок кода в синхронизированный блок

Пример::

Synchronized(Object)

{

----Instructions-----

}

Я чувствую, что синхронизированный блок лучше, чем весь метод

синхронизированный

Другие вопросы по тегам