servlet的每个实例与servlet中每个servlet的线程之间的区别?
有多个servlet类的实例吗? 正如我听到“servlet的每个实例”能有人详细说明吗?
当Servlet容器启动时,它:
- 读取
web.xml
; - 在类path中find已声明的Servlet; 和
- 加载和实例化每个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.
这些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实例variables,而只是将方法局部variables分配。 例如
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中使用实例variables,除了应用程序范围的值,通常从上下文参数获得。
- 不要使方法在一个servlet中
synchronized
(同样适用于servletfilter和jsps)
根据Java Servlet Specification Version 3.0(第6-7页),每个JVM每个声明将会有一个实例,除非servlet实现了SingleThreadModel,在这种情况下每个JVM可能有多个实例。
不能有多个servlet类的实例。 即使有一个servlet实例,也可以处理多个请求。 所以不使用类级variables是明智的。
对于那些知道真正的JavaScript(不只是它的库)的人来说,Servlet可以被看作是函数对象 。 作为功能对象,它们的主要任务是做一些事情 ,而不是在胸前存储一些信息 。 没有必要实例化每个这样的function对象的多个实例,其原理与Java类方法在该类的所有实例中共享的原理相同。
尽pipe已经有了一些很好的答案,但是他们都没有提到部署在分布式环境中的Java Web应用程序。 这是一个实际的场景,其中实际上创build了一个servlet的多个实例。 在分布式环境中,您有一组机器来处理请求,请求可以转到这些机器中的任何一台。 这些机器中的每一个都应该能够处理请求,因此每台机器都应该在其JVM中有一个MyAwesomeServlet的实例。
所以,正确的语句是每个JVM只有一个实例,除非它实现了SingleThreadModel。
SimpleThreadModel用简单的话来说,你必须每个Servlet实例只有一个线程,所以基本上你需要为每个处理请求创build一个实例,这基本上杀死了处理请求的整个概念,在servlet对象的创build和初始化需要时间才能处理请求之前考虑了一个好的做法。