当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模式时重用。 servlet容器然后执行类似于下面的代码:
for (Entry entry : servlets.entrySet()) {
String urlPattern = entry.getKey();
HttpServlet servlet = entry.getValue();
if (request.getRequestURL().matches(urlPattern)) {
servlet.service(request, response);
break;
}
}
你看,servletcontainer为每个请求重用相同的servlet实例。换句话说:servlet在每个请求之间共享。这就是为什么以线程安全的方式编写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.
}
}