servlet的每个实例与servlet中的每个servlet线程之间的区别?

gir*_*iri 83 java servlets

是否有多个servlet类实例?当我听到"servlet的每个实例"时,任何人都可以详细说明吗?

Bal*_*usC 186

当Servlet容器启动时,它:

  1. 读取web.xml;
  2. 在类路径中查找声明的Servlet; 和
  3. 加载并实例化每个Servlet 只一次.

粗略地,像这样:

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

这些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;
    }
}
Run Code Online (Sandbox Code Playgroud)

GenericServlet#service()其反过来决定哪些的doGet(),doPost()等等.要调用基于HttpServletRequest#getMethod().

您看,servletcontainer 为每个请求重用相同的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.
    } 
}
Run Code Online (Sandbox Code Playgroud)

  • +1.我将添加如果相同的servlet类映射到web.xml中的两个不同的URL,则会创建两个实例.但是一般原则仍然存在,一个实例提供多个请求. (21认同)

Boz*_*zho 30

不,只有一个servlet实例可以重用于来自多个客户端的多个请求.这导致两个重要规则:

  • 不要在servlet中使用实例变量,除了应用程序范围的值,通常从上下文参数中获取.
  • 不要synchronized在servlet中创建方法

(同样适用于servlet过滤器和jsps)


Sam*_*ard 11

根据Java Servlet规范版本3.0(第6-7页),每个JVM每个声明将有一个实例,除非servlet实现SingleThreadModel,在这种情况下,每个JVM可能有多个实例.


Sau*_*til 6

虽然已经有一些很好的答案,但没有一个人谈到在分布式环境中部署的Java Web应用程序.这是一个实际场景,其中实际创建了单个servlet的多个实例.在分布式环境中,您有一组机器来处理请求,请求可以转到任何这些机器.这些机器中的每一台都应该能够处理请求,因此每台机器都应该在其JVM中有一个MyAwesomeServlet实例.

因此,正确的说法是每个servlet只有一个实例用于每个servlet,除非它实现了SingleThreadModel.

SingleThreadModel简单地说每个Servlet实例只需要一个线程,所以基本上你需要为每个处理它的请求创建一个实例,这基本上会杀死以并行方式处理请求的整个概念而不是因为servlet对象创建和初始化在准备好处理请求之前占用了时间,所以这被认为是一种很好的做法.


fas*_*ava 5

servlet类不能有多个实例.即使有一个servlet实例,它也能够处理多个请求.因此,不使用类级变量是明智的.


lcn*_*lcn 5

对于那些了解真正的 JavaScript(而不仅仅是 JavaScript 库)的人来说,Servlet 可以被视为函数对象。作为功​​能性物体,它们的主要任务是做某事,而不是在胸中存储一些信息。不需要实例化每个这样的函数对象的多个实例,这与 Java 类方法在该类的所有实例之间共享的原理相同。