Разница между каждым экземпляром сервлета и каждым потоком сервлета в сервлетах?
Есть ли несколько экземпляров класса сервлета? Когда я слышу "каждый экземпляр сервлета",
Может ли кто-нибудь это уточнить?
Ответы
Ответ 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 в простых словах говорит, что для каждого экземпляра сервлета необходимо иметь только один поток, поэтому в основном вам нужно создать один экземпляр для каждого запроса для его обработки, что в основном уничтожает всю концепцию обработки запросов параллельно и не считается хорошей практикой, так как создание и инициализация объекта сервлета занимает время до его готовности к обработке запроса.