Разница между каждым экземпляром сервлета и каждым потоком сервлета в сервлетах?
Есть ли несколько экземпляров класса сервлетов? Как я слышу "каждый экземпляр сервлета" Кто-нибудь может уточнить это?
6 ответов
Когда контейнер сервлетов запускается, он:
- читает
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-адрес запроса соответствует связанному сервлету 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.
}
}
Нет, существует только один экземпляр сервлета, который повторно используется для нескольких запросов от нескольких клиентов. Это приводит к двум важным правилам:
- не используйте переменные экземпляра в сервлете, за исключением значений для всего приложения, чаще всего получаемых из параметров контекста.
- не делай методов
synchronized
в сервлете
(то же самое касается фильтров сервлетов и jsps)
В соответствии со спецификацией Java Servlet версии 3.0 (стр. 6-7), будет один экземпляр для каждого объявления в JVM, если сервлет не реализует SingleThreadModel, и в этом случае может быть несколько экземпляров в JVM.
Хотя уже есть несколько хороших ответов, ни один из них не говорил о веб-приложении Java, развернутом в распределенной среде. Это практический сценарий, когда фактически создается несколько экземпляров одного сервлета. В распределенной среде у вас есть кластер машин для обработки запроса, и запрос может отправляться на любую из этих машин. Каждая из этих машин должна быть способна обработать запрос, и, следовательно, на каждой машине должен быть экземпляр вашего MyAwesomeServlet в его JVM.
Таким образом, правильный оператор будет иметь только один экземпляр для каждой виртуальной машины Java для каждого сервлета, если только он не реализует SingleThreadModel.
SingleThreadModel в простых словах говорит о том, что вам нужно иметь только один поток на экземпляр Servlet, поэтому в основном вам нужно создать один экземпляр для каждого поступающего запроса, чтобы обработать его, что в основном убивает всю концепцию обработки запросов параллельно и не считается хорошей практикой, поскольку создание и инициализация объекта сервлета занимает много времени, прежде чем он будет готов обработать запрос.
Не может быть нескольких экземпляров класса сервлета. Даже при наличии одного экземпляра сервлета он может обрабатывать несколько запросов. Поэтому не стоит использовать переменные уровня класса.
Для тех, кто знает настоящий JavaScript (а не просто его библиотеку), сервлеты можно рассматривать как функциональные объекты. Как функциональные объекты, их главная задача - что-то делать, а не хранить некоторую информацию в своих сундуках. Нет необходимости создавать более одного экземпляра каждого такого функционального объекта с тем же обоснованием, что методы класса Java являются общими для всех экземпляров этого класса.