Servlet 的每个实例和 servlet 中的每个线程之间的差异?

有多个 servlet 类实例吗 有人能解释一下吗?

43806 次浏览

No, there is only one instance of the servlet which is reused for multiple requests from multiple clients. This leads to two important rules:

  • don't use instance variables in a servlet, except for application-wide values, most often obtained from context parameters.
  • don't make methods synchronized in a servlet

(same goes for servlet filters and jsps)

There can not be multiple instances of servlet class. Even when there is one instance of the servlet, it is able to handle multiple requests. So it is wise not to use class level variables.

When the Servlet container starts, it:

  1. reads web.xml;
  2. finds the declared Servlets in the classpath; and
  3. loads and instantiates each Servlet only once.

Roughly, like this:

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

Those Servlets are stored in memory and reused every time the request URL matches the Servlet's associated url-pattern. The servlet container then executes code similar to:

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

The GenericServlet#service() on its turn decides which of the doGet(), doPost(), etc.. to invoke based on HttpServletRequest#getMethod().

You see, the servletcontainer reuses the same servlet instance for every request. In other words: the servlets are shared among every request. That's why it's extremely important to write servlet code the threadsafe manner --which is actually simple: just do not assign request or session scoped data as servlet instance variables, but just as method local variables. 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.
}
}

According to the Java Servlet Specification Version 3.0 (pp. 6-7), there will be one instance per declaration per JVM, unless the servlet implements SingleThreadModel in which case there may be multiple instances per JVM.

For those that know real JavaScript (not just a library of it), Servlets can be viewed as function objects. As functional objects, the main task of them is to do something, instead of to store some information in their chests. There is no need to instantiate more than one instance of every such functional object, with the same rationale that Java class methods are shared among all instances of that class.

Although there are already a few good answers, none of them spoke about a Java web application deployed in a distributed environment. This is a practical scenario where actually multiple instances of a single servlet are created. In a distributed environment you have a cluster of machines to handle the request and the request can go to any of these machines. Each of these machines should be capable to handle the request and hence every machine should have an instance of your MyAwesomeServlet in it's JVM.

So, the correct statement would be there is only one instance per JVM for every servlet, unless it implements SingleThreadModel.

SingleThreadModel in simple words says that you have to have only one thread per instance of Servlet, so basically you need to create one instance per coming request to handle it, which basically kills the whole concept of handling requests in a parallel fashion and isn't considered a good practice as the servlet object creation and initialization takes up time before it's ready to process the request.