Разница между каждым экземпляром сервлета и каждым потоком сервлета в сервлетах?

Есть ли несколько экземпляров класса сервлета? Когда я слышу "каждый экземпляр сервлета", Может ли кто-нибудь это уточнить?

Ответ 1

Когда контейнер Servlet запускается, он:

  • читает web.xml;
  • находит объявленные сервлеты в пути к классам; и
  • загружает и создает каждый сервлет только один раз.

Примерно так:

String urlPattern = parseWebXmlAndRetrieveServletUrlPattern();
String servletClass = parseWebXmlAndRetrieveServletClass();
HttpServlet servlet = (HttpServlet) Class.forName(servletClass).newInstance();
servlet.init();
servlets.put(urlPattern, servlet); // Similar to a map interface.

Эти сервлеты хранятся в памяти и повторно используются каждый раз, когда URL-адрес запроса соответствует связанным с Servlet url-pattern. Затем контейнер сервлета выполняет код, похожий на:

for (Entry<String, HttpServlet> entry : servlets.entrySet()) {
    String urlPattern = entry.getKey();
    HttpServlet servlet = entry.getValue();
    if (request.getRequestURL().matches(urlPattern)) {
        servlet.service(request, response);
        break;
    }
}

GenericServlet#service() в свою очередь решает, какой из doGet(), doPost() и т.д. вызывать на основе HttpServletRequest#getMethod().

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

public class MyServlet 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.
    } 
}

Ответ 2

Нет, есть только один экземпляр сервлета, который повторно используется для нескольких запросов от нескольких клиентов. Это приводит к двум важным правилам:

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

(то же самое относится к фильтрам сервлетов и jsps)

Ответ 3

В соответствии с Java Servlet Specification Version 3.0 (стр. 6-7) на JVM будет один экземпляр для каждого объявления, если только сервлет не реализует SingleThreadModel, и в этом случае на JVM может быть несколько экземпляров.

Ответ 4

Не может быть нескольких экземпляров класса сервлета. Даже когда есть один экземпляр сервлета, он способен обрабатывать несколько запросов. Поэтому разумно не использовать переменные уровня класса.

Ответ 5

Для тех, кто знает реальный JavaScript (а не только его библиотеку), сервлеты можно рассматривать как объекты функций. В качестве функциональных объектов основная задача состоит в том, чтобы что-то делать, а не хранить некоторую информацию в сундуках. Нет необходимости создавать экземпляр нескольких экземпляров каждого такого функционального объекта с тем же обоснованием, что методы класса Java совместно используются для всех экземпляров этого класса.

Ответ 6

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

Итак, правильный оператор будет содержать только один экземпляр для JVM для каждого сервлета, если только он не реализует SingleThreadModel.

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