servlet如何工作?实例化,会话,共享变量和多线程

时间:2010-06-24 00:16:15

标签: java multithreading servlets session-variables instance-variables

假设我有一个拥有大量servlet的Web服务器。对于在这些servlet之间传递的信息,我正在设置会话和实例变量。

现在,如果有2个或更多用户向此服务器发送请求,那么会话变量会发生什么?它们对所有用户都是通用的,或者对于每个用户而言都是不同的。如果它们不同,那么服务器如何区分不同的用户?

另一个类似的问题,如果有n个用户访问某个特定的servlet,那么这个servlet只在第一个用户第一次访问它时实例化,或者是否为所有用户分别实例化?换句话说,实例变量会发生什么?

8 个答案:

答案 0 :(得分:1730)

答案 1 :(得分:417)

会话

enter image description here enter image description here

简而言之:Web服务器在首次访问时向每个访问者发出唯一标识符。访问者必须带回该ID,以便下次被识别。此标识符还允许服务器正确地将一个会话拥有的对象与另一个会话拥有的对象隔离。

Servlet实例化

如果加载启动 错误

enter image description here enter image description here

如果加载启动 为真

enter image description here enter image description here

一旦他处于服务模式和沟槽中,相同的 servlet将处理来自所有其他客户端的请求。

enter image description here

为什么每个客户端都有一个实例不是一个好主意?想一想:你会为每一个订单雇用一个披萨店吗?这样做,你很快就会破产。

虽然风险很小。记住:这个单身人士把所有的订单信息都放在口袋里:所以如果你对thread safety on servlets不小心,他最终可能会向某个客户发出错误的订单。

答案 2 :(得分:42)

Java servlets中的会话与其他语言(如PHP)中的会话相同。它对用户来说是独一无二的。服务器可以用不同的方式跟踪它,例如cookie,url重写等。这篇Java doc文章在Java servlet的上下文中解释它,并指出会话的确切维护是一个实现细节留给设计者服务器。规范仅规定必须通过与服务器的多个连接将其维护为对用户唯一。有关这两个问题的详细信息,请查看this article from Oracle

编辑关于如何在servlet中使用会话,有一个很好的教程here。而here是Sun关于Java Servlets的章节,它们是什么以及如何使用它们。在这两篇文章之间,您应该能够回答所有问题。

答案 3 :(得分:33)

当servlet容器(如Apache Tomcat)启动时,它将从web.xml文件中读取(每个应用程序只有一个),如果出现任何问题或在容器侧控制台上显示错误,否则,它将部署和使用web.xml加载所有Web应用程序(将其命名为部署描述符)。

在servlet的实例化阶段,servlet实例已准备就绪,但它无法为客户端请求提供服务,因为它缺少两条信息:
1:上下文信息
2:初始配置信息

Servlet引擎创建servletConfig接口对象,将上面缺少的信息封装到其中 servlet引擎通过提供servletConfig对象引用作为参数来调用servlet的init()。一旦init()完全执行,servlet就可以为客户端请求提供服务。

问)在servlet的生命周期中,实例化和初始化发生了多少次?

A)只有一次(为每个客户端请求创建一个新线程) 只有一个servlet实例服务于任意数量的客户端请求,即在服务一个客户端请求后,服务器不会死亡。它等待其他客户端请求,即使用servlet(内部servlet引擎创建线程)克服了CGI(为每个客户端请求创建新进程)的限制。

问)会话概念如何运作?

A)每当在HttpServletRequest对象上调用getSession()时

第1步:评估请求对象的传入会话ID。

步骤2 :如果ID不可用,则创建一个全新的HttpSession对象并生成其对应的会话ID(即HashTable)会话ID存储到httpservlet响应对象和HttpSession对象的引用返回到servlet(doGet / doPost)。

步骤3 :如果未创建ID可用的全新会话对象,则从请求对象中拾取会话ID,使用会话ID作为密钥在会话集合中进行搜索。

搜索成功后,会话ID将存储到HttpServletResponse中,现有会话对象引用将返回给UserDefineservlet的doGet()或doPost()。

注意:

1)当控件从servlet代码离开到客户端时,不要忘记servlet容器(即servlet引擎)正在保存会话对象

2)多线程留给servlet开发人员实现ie。,处理客户端的多个请求没什么好打扰多线程代码

Inshort表格:

在应用程序启动时(它部署在servlet容器上)或首次访问时创建一个servlet(取决于load-on-startup设置) 实例化servlet时,调用servlet的init()方法 然后servlet(它的唯一实例)处理所有请求(由多个线程调用其service()方法)。这就是为什么不建议在其中进行任何同步,并且应该避免使用servlet的实例变量 取消部署应用程序时(servlet容器停止),将调用destroy()方法。

答案 4 :(得分:20)

会话 - Chris Thompson说的话。

实例化 - 当容器收到映射到servlet的第一个请求时,实例化servlet(除非servlet配置为在启动时使用<load-on-startup>元素加载web.xml })。相同的实例用于为后续请求提供服务。

答案 5 :(得分:13)

Servlet规范 JSR-315 清楚地定义了服务(和doGet,doPost,doPut等)方法中的Web容器行为(2.3.3.1多线程问题,第9页):

  

servlet容器可以通过服务发送并发请求   servlet的方法。为了处理请求,Servlet Developer   必须为多个并发处理做出充分准备   服务方法中的线程。

     

虽然不推荐,但开发人员的替代方案是   实现需要容器的SingleThreadModel接口   保证一次只有一个请求线程   服务方式。 servlet容器可满足此要求   序列化servlet上的请求,或者维护一个servlet池   实例。如果servlet是已经存在的Web应用程序的一部分   标记为可分发的容器可以维护一个servlet池   应用程序分布在每个JVM中的实例。

     

对于没有实现SingleThreadModel接口的servlet,如果是   服务方法(或doGet或doPost等方法   调度到HttpServlet抽象类的服务方法)   已使用synchronized关键字servlet容器定义   不能使用实例池方法,但必须序列化请求   通过它。强烈建议开发人员不要同步   这些中的服务方法(或调度给它的方法)   情况因为对绩效的不利影响

答案 6 :(得分:0)

从上面的说明中可以清楚地看出,

通过实现 SingleThreadModel ,可以通过servlet容器确保servlet的线程安全。容器实现可以通过两种方式做到这一点:

1)将请求序列化(排队)到单个实例-这类似于未实现SingleThreadModel的servlet,但是无法同步service / doXXX方法;或

2)创建实例池-这是一个更好的选择,并且是在Servlet的启动/初始化工作/时间与托管Servlet的环境的限制性参数(内存/ CPU时间)之间进行权衡的选择

答案 7 :(得分:-1)

否。 Servlet 非线程安全

这允许一次访问多个线程

如果你想把它作为线程安全的Servlet。,你可以去

Implement SingleThreadInterface(i) 这是一个空白的界面没有

方法

或者我们可以选择同步方法

我们可以使用synchronized

使整个服务方法同步 方法前面的

关键字

示例::

public Synchronized class service(ServletRequest request,ServletResponse response)throws ServletException,IOException

或者我们可以在Synchronized块中放置代码块

示例::

Synchronized(Object)

{

----Instructions-----

}

我觉得同步块比制作整个方法更好

同步