假设,我有一个包含大量servlet的web服务器。对于在这些servlet之间传递的信息,我设置了会话和实例变量。
现在,如果2个或更多用户向这个服务器发送请求,那么会话变量会发生什么变化? 它们对所有用户都是通用的,还是对每个用户都是不同的? 如果它们是不同的,那么服务器如何区分不同的用户?
还有一个类似的问题,如果有n个用户访问一个特定的servlet,那么这个servlet只在第一个用户第一次访问它时实例化,还是为所有用户分别实例化? 换句话说,实例变量会发生什么变化?
假设,我有一个包含大量servlet的web服务器。对于在这些servlet之间传递的信息,我设置了会话和实例变量。
现在,如果2个或更多用户向这个服务器发送请求,那么会话变量会发生什么变化? 它们对所有用户都是通用的,还是对每个用户都是不同的? 如果它们是不同的,那么服务器如何区分不同的用户?
还有一个类似的问题,如果有n个用户访问一个特定的servlet,那么这个servlet只在第一个用户第一次访问它时实例化,还是为所有用户分别实例化? 换句话说,实例变量会发生什么变化?
当前回答
Servlet规范JSR-315明确定义了服务(以及doGet、doPost、doPut等)方法中的web容器行为(2.3.3.1多线程问题,第9页):
A servlet container may send concurrent requests through the service method of the servlet. To handle the requests, the Servlet Developer must make adequate provisions for concurrent processing with multiple threads in the service method. Although it is not recommended, an alternative for the Developer is to implement the SingleThreadModel interface which requires the container to guarantee that there is only one request thread at a time in the service method. A servlet container may satisfy this requirement by serializing requests on a servlet, or by maintaining a pool of servlet instances. If the servlet is part of a Web application that has been marked as distributable, the container may maintain a pool of servlet instances in each JVM that the application is distributed across. For servlets not implementing the SingleThreadModel interface, if the service method (or methods such as doGet or doPost which are dispatched to the service method of the HttpServlet abstract class) has been defined with the synchronized keyword, the servlet container cannot use the instance pool approach, but must serialize requests through it. It is strongly recommended that Developers not synchronize the service method (or methods dispatched to it) in these circumstances because of detrimental effects on performance
其他回答
Servlet规范JSR-315明确定义了服务(以及doGet、doPost、doPut等)方法中的web容器行为(2.3.3.1多线程问题,第9页):
A servlet container may send concurrent requests through the service method of the servlet. To handle the requests, the Servlet Developer must make adequate provisions for concurrent processing with multiple threads in the service method. Although it is not recommended, an alternative for the Developer is to implement the SingleThreadModel interface which requires the container to guarantee that there is only one request thread at a time in the service method. A servlet container may satisfy this requirement by serializing requests on a servlet, or by maintaining a pool of servlet instances. If the servlet is part of a Web application that has been marked as distributable, the container may maintain a pool of servlet instances in each JVM that the application is distributed across. For servlets not implementing the SingleThreadModel interface, if the service method (or methods such as doGet or doPost which are dispatched to the service method of the HttpServlet abstract class) has been defined with the synchronized keyword, the servlet container cannot use the instance pool approach, but must serialize requests through it. It is strongly recommended that Developers not synchronize the service method (or methods dispatched to it) in these circumstances because of detrimental effects on performance
Session in Java servlets is the same as session in other languages such as PHP. It is unique to the user. The server can keep track of it in different ways such as cookies, url rewriting etc. This Java doc article explains it in the context of Java servlets and indicates that exactly how session is maintained is an implementation detail left to the designers of the server. The specification only stipulates that it must be maintained as unique to a user across multiple connections to the server. Check out this article from Oracle for more information about both of your questions.
这里有一个关于如何在servlet中使用session的优秀教程。这里有来自Sun的一章关于Java servlet,它们是什么以及如何使用它们。在这两篇文章之间,你应该能够回答你所有的问题。
当servlet容器(如Apache Tomcat)启动时,如果出现任何错误或在容器端控制台显示错误,它将从web.xml文件中读取(每个应用程序只有一个),否则,它将使用web.xml(因此将其命名为部署描述符)部署和加载所有web应用程序。
在servlet实例化阶段,servlet实例已经准备好了,但是它不能为客户端请求服务,因为它缺少两个信息: 1:上下文信息 2:初始配置信息
Servlet引擎创建servletConfig接口对象,其中封装了上述缺失的信息 servlet引擎通过提供servletConfig对象引用作为参数来调用servlet的init()。一旦init()完全执行,servlet就准备好为客户端请求服务了。
Q)在servlet的生命周期中,实例化和初始化发生了多少次?
A)只有一次(对于每个客户端请求都创建一个新线程) 只有一个servlet实例服务于任意数量的客户端请求,即服务一个客户端请求后服务器不会死亡。它等待其他客户端请求,即CGI(每个客户端请求都会创建一个新进程)的限制被servlet(内部servlet引擎创建线程)克服。
Q)会话概念是如何工作的?
A)每当在HttpServletRequest对象上调用getSession()时
步骤1:评估请求对象的传入会话ID。
第二步:如果ID不可用,则创建一个全新的HttpSession对象,并生成相应的会话ID(即HashTable)。会话ID存储在httpservlet响应对象中,HttpSession对象的引用返回给servlet (doGet/doPost)。
第三步:如果ID可用,没有创建全新的会话对象,则从请求对象中获取会话ID,以会话ID为键在会话集合中进行搜索。
一旦搜索成功,会话ID将存储到HttpServletResponse中,现有的会话对象引用将返回到UserDefineservlet的doGet()或doPost()。
注意:
1)当控制从servlet代码转移到客户端时,不要忘记会话对象是由servlet容器(即servlet引擎)保存的
2)多线程留给servlet开发人员去实现ie。,处理客户端的多个请求,不用担心多线程代码
简称:
A servlet is created when the application starts (it is deployed on the servlet container) or when it is first accessed (depending on the load-on-startup setting) when the servlet is instantiated, the init() method of the servlet is called then the servlet (its one and only instance) handles all requests (its service() method being called by multiple threads). That's why it is not advisable to have any synchronization in it, and you should avoid instance variables of the servlet when the application is undeployed (the servlet container stops), the destroy() method is called.
从上面的解释可以清楚地看出,通过实现SingleThreadModel, servlet容器可以确保servlet的线程安全。容器实现可以通过两种方式做到这一点:
1)序列化请求(排队)到单个实例——这类似于servlet不实现SingleThreadModel,但同步service/ doXXX方法;或
2)创建一个实例池——这是一个更好的选择,可以在servlet的启动/初始化工作/时间与托管servlet的环境的限制性参数(内存/ CPU时间)之间进行权衡。
会话
简而言之:web服务器在每个访问者第一次访问时向其发出唯一标识符。访客必须带回来这个ID,以便下次来的时候能被认出来。这个标识符还允许服务器正确地将一个会话拥有的对象与另一个会话拥有的对象隔离。
Servlet实例化
如果load-on-startup为false:
如果load-on-startup为true:
一旦他进入服务模式并处于最佳状态,同一个servlet将处理来自所有其他客户机的请求。
为什么每个客户端有一个实例不是一个好主意?想想看:你会为每一份披萨订单雇一个送披萨的吗?那样做的话,你很快就会破产。
但这也有一个小风险。记住:这个家伙把所有的订单信息都放在他的口袋里:因此,如果您不注意servlet上的线程安全,他可能最终会向某个客户端发出错误的订单。