Servlet类是否有多个实例?当我听到“每个servlet实例”时,有人可以详细解释一下吗?
当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.
这些Servlet存储在内存中,并且每当请求的URL与Servlet的关联的url-pattern
匹配时就会被重复使用。 然后,servlet容器执行类似以下代码的代码:
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;
}
}
根据 HttpServletRequest#getMethod()
的不同,GenericServlet#service()
将决定调用哪个方法,如 doGet()
、doPost()
等等。
你看,servlet 容器为每个请求重复使用同一个 servlet 实例。换句话说:servlet 在每个请求之间共享。这就是为什么编写线程安全的 servlet 代码非常重要,实际上很简单:只需将请求或会话作用域数据分配为方法局部变量而不是作为 servlet 实例变量。例如:
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.
}
}
thisIsNOTThreadSafe
将在会话之间共享。即使您注销并重新登录。 - Ricardo不,servlet只有一个实例,可以为来自多个客户端的多个请求重复使用。这导致两个重要规则:
synchronized
(相同的规则也适用于servlet过滤器和JSP)
/foo
和/bar
),那么您将拥有两个MyAwesomeServlet
类定义的副本,实际上,在同一时间内在内存中有两个MyAwesomeServlet
实例。因此,每个JVM实际上可以有多个servlet实例。请注意,JVM认为这些是不同的类,因为它们由不同的ClassLoader加载。Servlet规范需要一个单独的ClassLoader,并且概念类=“ClassLoader+Class”通常适用于Java。 - Christopher Schultz一个servlet类不能有多个实例。即使只有一个servlet实例,它也能处理多个请求。因此,最好不要使用类级别的变量。
对于那些了解真正的JavaScript(而不仅仅是它的库)的人来说,Servlets可以被视为函数对象。作为功能对象,它们的主要任务是做某些事情,而不是在它们的胸膛中存储一些信息。没有必要实例化每个这样的功能对象的多个实例,与Java类方法在该类的所有实例之间共享的原理相同。