Servlet容器启动时,它:
- 读
web.xml
; - 在类路径中找到已声明的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()其反过来决定其中
doGet(),
doPost()要调用基础上,等
HttpServletRequest#getMethod()。
您会看到,servlet容器为每个请求重用了相同的servlet实例。换句话说:servlet在每个request之间共享。这就是为什么它是要编写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. } }


