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

时间:2010-02-02 12:33:50

标签: java servlets

是否有多个servlet类实例?我听到“每个servlet实例” 任何人都可以详细说明这个吗?

6 个答案:

答案 0 :(得分:185)

当Servlet容器启动时,它:

  1. 读取web.xml;
  2. 在类路径中查找声明的Servlet;和
  3. 仅加载并实例化每个Servlet
  4. 粗略地说,像这样:

    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;
        }
    }
    

    轮次GenericServlet#service()决定根据HttpServletRequest#getMethod()调用doGet()doPost()等中的哪一个。

    您会看到,servletcontainer为每个请求重用相同的servlet实例。换句话说:servlet在每个请求之间共享。这就是为什么以线程安全的方式编写servlet代码非常重要 - 这实际上很简单:只需要​​将请求或会话范围的数据分配为servlet实例变量,而只是作为方法局部变量。 E.g。

    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.
        } 
    }
    

答案 1 :(得分:30)

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

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

(对于servlet过滤器和jsps也一样)

答案 2 :(得分:11)

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

答案 3 :(得分:6)

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

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

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

答案 4 :(得分:5)

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

答案 5 :(得分:4)

对于那些了解真正的JavaScript(不仅仅是它的库)的人来说,可以将Servlets视为功能对象。作为功​​能对象,它们的主要任务是做某事,而不是将一些信息存储在它们的箱子里。没有必要实例化每个这样的功能对象的多个实例,其基本原理是Java类方法在该类的所有实例之间共享。