关于java:servlet的每个实例与servlet中每个servlet线程之间的区别?

Difference between each instance of servlet and each thread of servlet in servlets?

本问题已经有最佳答案,请猛点这里访问。

servlet类有多个实例吗?正如我听到的"servlet的每个实例"有人能详细解释一下吗?


当servlet容器启动时,它:

  • 读取web.xml
  • 在类路径中查找声明的servlet;以及
  • 只加载和实例化每个servlet一次。
  • 大致如此:

    1
    2
    3
    4
    5
    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容器随后执行类似以下代码:

    1
    2
    3
    4
    5
    6
    7
    8
    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为每个请求重用相同的servlet实例。换句话说:servlet在每个请求之间共享。这就是为什么编写servlet代码的方式非常重要——实际上很简单:不要将请求或会话范围的数据分配为servlet实例变量,而是将其作为方法局部变量。例如。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    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.
        }
    }


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

    • 不要在servlet中使用实例变量,应用程序范围的值除外,这些值通常是从上下文参数获得的。
    • 不要在servlet中生成方法synchronized

    (servlet过滤器和jsp也是如此)


    根据JavaServlet规范3版(pp.6-7),除非JavaRead模型实现每个JVM的多个实例,否则每个JVM每个声明将有一个实例。


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

    因此,正确的语句应该是每个servlet的每个JVM只有一个实例,除非它实现了singlethreadmodel。

    简单来说,singlethreadmodel表示,每个servlet实例只能有一个线程,因此基本上需要为每个即将到来的请求创建一个实例来处理它,这基本上扼杀了以并行方式处理请求的整个概念,并且作为servlet对象的创建和初始化并不被认为是一个好的实践。在准备好处理请求之前需要花费一些时间。


    servlet类不能有多个实例。即使有一个servlet实例,它也能够处理多个请求。所以最好不要使用类级变量。


    对于那些知道真正的javascript(不仅仅是它的库)的用户,servlet可以被看作是函数对象。作为功能对象,它们的主要任务是做一些事情,而不是在胸部存储一些信息。不需要实例化每个这样的函数对象的一个实例,其原理与Java类方法在该类的所有实例之间共享的原理相同。