Answers:
当servlet容器(如Apache Tomcat)启动时,它将部署并加载其所有Web应用程序。加载Web应用程序后,Servlet容器将创建ServletContext
一次并将其保存在服务器的内存中。Web应用程序的web.xml
所有包含的web-fragment.xml
文件进行解析,每个<servlet>
,<filter>
和<listener>
发现(或每一类注释用@WebServlet
,@WebFilter
并@WebListener
分别)被实例化一次,并保存在服务器的内存。对于每个实例化的过滤器,其init()
方法都通过new调用FilterConfig
。
当a的Servlet
a <servlet><load-on-startup>
或@WebServlet(loadOnStartup)
value大于时0
,则init()
在启动期间还会使用new调用其方法ServletConfig
。这些servlet以该值指定的相同顺序进行初始化(1
为1st,2
为2nd等)。如果多于一个的servlet指定了相同的值,则每个这些小服务程序的如它们出现在加载以相同的顺序web.xml
,web-fragment.xml
或@WebServlet
类加载。如果没有“启动时加载”值,则init()
当HTTP请求首次访问该servlet时,将调用该方法。
当Servlet容器完成上述所有初始化步骤后,ServletContextListener#contextInitialized()
将调用。
当servlet容器关闭时,它卸载所有Web应用程序,调用destroy()
其全部初始化servlet和过滤器,所有的方法ServletContext
,Servlet
,Filter
和Listener
实例丢弃。最后,ServletContextListener#contextDestroyed()
将被调用。
Servlet容器连接到Web服务器,该Web服务器在某个端口号上侦听HTTP请求(端口8080通常在开发过程中使用,而端口80在生产中使用)。当客户端(例如,具有Web浏览器的用户,或以编程方式使用的用户URLConnection
)发送HTTP请求时,Servlet容器将创建new HttpServletRequest
和HttpServletResponse
对象,并将它们通过Filter
链中定义的任何对象以及Servlet
实例进行传递。
对于filter,将doFilter()
调用该方法。当servlet容器的代码调用时chain.doFilter(request, response)
,请求和响应将继续到下一个过滤器,如果没有剩余的过滤器,则单击servlet。
对于servlet,将service()
调用该方法。默认情况下,此方法根据of确定doXxx()
要调用的方法之一 request.getMethod()
。如果servlet中没有确定的方法,则在响应中返回HTTP 405错误。
request对象提供对有关HTTP请求的所有信息的访问,例如URL,标头,查询字符串和正文。响应对象提供了以所需方式控制和发送HTTP响应的功能,例如,允许您设置标头和正文(通常使用从JSP文件生成的HTML内容)。提交并完成HTTP响应后,请求和响应对象都将被回收并可供重用。
当客户端第一次访问webapp和/或HttpSession
通过首次获得时request.getSession()
,servlet容器会创建一个新HttpSession
对象,生成一个长而唯一的ID(您可以通过获取session.getId()
),并将其存储在服务器的记忆。Servlet容器还在HTTP响应Cookie
的Set-Cookie
标头中设置a JSESSIONID
作为其名称,并将唯一会话ID作为其值。
根据HTTP cookie规范(任何体面的Web浏览器和Web服务器都必须遵守的合同),Cookie
只要cookie有效(也就是说,唯一ID必须指向未过期的会话,并且域和路径正确)。使用浏览器的内置HTTP流量监控器,您可以验证Cookie是否有效(在Chrome / Firefox 23 + / IE9 +中按F12,然后检查“ 网络/网络”标签)。Servlet容器将检查Cookie
每个传入HTTP请求的标头中是否存在具有该名称的cookie,JSESSIONID
并使用其值(会话ID)HttpSession
从服务器的内存中获取关联。
的HttpSession
活,直到它停留已经空闲(即,在请求未使用)超过规定的超时值<session-timeout>
,在设定web.xml
。超时值默认为30分钟。因此,当客户端访问Web应用程序的时间不超过指定的时间时,Servlet容器将破坏会话。每个后续请求,即使指定了cookie,也将无法再访问同一会话。Servlet容器将创建一个新会话。
在客户端,只要浏览器实例正在运行,会话cookie就会保持活动状态。因此,如果客户端关闭浏览器实例(所有选项卡/窗口),则会话将被丢弃在客户端侧。在新的浏览器实例中,与会话关联的cookie将不存在,因此将不再发送。这将导致HttpSession
创建一个全新的会话,并使用一个全新的会话cookie。
ServletContext
生活,只要Web应用程序的生命。它在所有会话的所有请求之间共享。HttpSession
生活,只要客户端与同一个浏览器实例中的Web应用程序进行交互,和会话未在服务器端超时。它在同一会话的所有请求之间共享。HttpServletRequest
和HttpServletResponse
现场从servlet接收来自客户端的HTTP请求的时间,直到完全缓解(网页)已经到来。它没有在其他地方共享。Servlet
,所有Filter
和Listener
实例都会存在。它们在所有会话的所有请求之间共享。attribute
被定义ServletContext
,HttpServletRequest
并且HttpSession
只要将生活中的问题生活中的对象。对象本身代表了诸如JSF,CDI,Spring等之类的bean管理框架中的“作用域”。这些框架将其范围内的bean作为attribute
其最接近的匹配范围存储。也就是说,您最关心的可能是线程安全。现在,您应该知道所有请求都共享servlet和过滤器。这对Java来说是一件好事,它是多线程的,并且不同的线程(阅读:HTTP请求)可以使用同一实例。否则,重新创建init()
以及destroy()
针对每个单个请求的重新创建将过于昂贵。
您还应该认识到,切勿将任何请求或会话范围的数据分配为Servlet或过滤器的实例变量。它将在其他会话中的所有其他请求之间共享。那不是线程安全的!下面的示例说明了这一点:
public class ExampleServlet 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.
}
}
总之:Web服务器发出一个唯一的标识符,以每位游客在他的第一次访问。访客必须带回该ID,以便下次被识别。该标识符还允许服务器将一个会话所拥有的对象与另一个会话所拥有的对象正确地隔离开。
如果启动时加载为false:
如果启动时加载为true:
一旦他进入了服务模式并参与了工作,同一个 servlet将处理来自所有其他客户端的请求。
每个客户端一个实例为什么不是一个好主意?考虑一下:您会为每份订单雇用一个披萨人吗?这样做,您很快就会破产。
不过,它带来的风险很小。记住:这个单身汉将所有订单信息都放在口袋里:因此,如果您对servlet的线程安全性不太谨慎,他可能最终会给某个客户错误的订单。
to many requests at this moment. try again later
Java Servlet中的会话与其他语言(例如PHP)中的会话相同。它是用户唯一的。服务器可以以不同的方式(例如cookie,URL重写等)来跟踪它。此Java文档文章在Java servlet的上下文中对其进行了说明,并指出会话的确切维护方式是服务器设计者的实现细节。该规范仅规定,必须在与服务器的多个连接上将其维护为对用户唯一。从Oracle查阅本文,以获取有关这两个问题的更多信息。
编辑这里有一个很好的教程,介绍如何在servlet内部使用会话。而这里是来自Sun关于Java Servlet的,它们是什么,以及如何使用它们的一章。在这两篇文章之间,您应该能够回答所有问题。
ServletContext
对象。该对象具有零个,一个或多个会话对象-会话对象的集合。每个会话都由某种标识符字符串标识,如其他答案的卡通插图所示。该标识符通过cookie或URL重写在客户端上进行跟踪。每个会话对象都有其自己的变量。
当servlet容器(例如Apache Tomcat)启动时,它将从web.xml文件中读取(每个应用程序仅一个),如果出现任何错误或在容器侧控制台显示错误,否则它将部署并加载所有Web使用web.xml(因此将其称为部署描述符)的应用程序。
在Servlet的实例化阶段,servlet实例已准备就绪,但由于缺少以下两条信息而无法满足客户端请求:
1:上下文信息
2:初始配置信息
Servlet引擎创建ServletConfig接口对象,将上面缺少的信息封装到其中,通过提供ServletConfig对象引用作为参数,Servlet引擎调用Servlet的init()。一旦init()完全执行,servlet就准备好处理客户请求。
A)仅一次(对于每个客户端请求,都会创建一个新线程),只有Servlet的一个实例为任意数量的客户端请求服务,即,在为一个客户端请求服务后服务器不会死亡。它等待其他客户端请求,即Servlet克服了什么CGI(对于每个客户端请求创建了一个新进程)限制(内部servlet引擎创建了线程)。
A)每当在HttpServletRequest对象上调用getSession()时
步骤1:评估请求对象的传入会话ID。
步骤2:如果没有可用的ID,则会创建一个全新的HttpSession对象,并生成其相应的会话ID(即HashTable的会话ID),将会话ID存储到httpservlet响应对象中,并将HttpSession对象的引用返回给servlet(doGet / doPost) 。
步骤3:如果未创建ID可用的全新会话对象,则使用会话ID作为关键字,从请求对象中检索会话ID,以在会话集合中进行搜索。
一旦搜索成功,会话ID将存储到HttpServletResponse中,并且现有会话对象引用将返回到UserDefineservlet的doGet()或doPost()。
1)当控制权从Servlet代码移到客户端时,请不要忘记会话对象由servlet容器(即servlet引擎)持有。
2)多线程处理留给servlet开发人员来实现,即处理客户端的多个请求而不必担心多线程代码
实例化servlet时,在应用程序启动(部署在servlet容器上)或首次访问(取决于启动时加载设置)时创建servlet,该servlet的init()方法被调用然后servlet(它的一个也是唯一的实例)处理所有请求(它的service()方法被多个线程调用)。这就是为什么不建议在其中进行任何同步的原因,并且在取消部署应用程序(Servlet容器停止)时,应避免使用Servlet的实例变量,并调用destroy()方法。
会议 -克里斯·汤普森说的。
实例化 -当容器接收到映射到Servlet的第一个请求时,实例化Servlet(除非Servlet被配置为在启动时使用中的<load-on-startup>
元素加载web.xml
)。相同的实例用于处理后续请求。
Servlet规范JSR-315明确定义了服务(以及doGet,doPost,doPut等)方法中的Web容器行为(2.3.3.1多线程问题,第9页):
Servlet容器可以通过Servlet的服务方法发送并发请求。为了处理请求,Servlet开发人员必须为服务方法中的多线程并发处理做好充分的准备。
尽管不建议这样做,但开发人员的另一种选择是实现SingleThreadModel接口,该接口要求容器保证服务方法中一次仅存在一个请求线程。Servlet容器可以通过序列化Servlet上的请求或维护Servlet实例池来满足此要求。如果servlet是已标记为可分发的Web应用程序的一部分,则容器可以在应用程序分布在的每个JVM中维护一个servlet实例池。
对于未实现SingleThreadModel接口的servlet,如果已使用synced关键字定义了服务方法(或分派到HttpServlet抽象类的服务方法的doGet或doPost之类的方法),则servlet容器不能使用实例池方法,但必须通过它序列化请求。强烈建议开发人员在这种情况下不要同步服务方法(或分派给它的方法),因为这会对性能产生不利影响。
从上面的解释中可以清楚地看出,通过实现SingleThreadModel,可以通过servlet容器确保servlet的线程安全性。容器实现可以通过两种方式做到这一点:
1)将请求(排队)序列化到单个实例-这类似于未实现SingleThreadModel的servlet,但要同步service / doXXX方法;要么
2)创建实例池-这是一个更好的选择,并且是在Servlet的启动/初始化工作量/时间与托管Servlet的环境的限制性参数(内存/ CPU时间)之间进行权衡的选择。
否。Servlet 不是线程安全的
这允许一次访问多个线程
如果您想使其Servlet作为线程安全。,您可以选择
Implement SingleThreadInterface(i)
这是一个空白接口,没有
方法
或者我们可以使用同步方法
我们可以通过使用同步使整个服务方法成为同步的
方法前面的关键字
例::
public Synchronized class service(ServletRequest request,ServletResponse response)throws ServletException,IOException
或者我们可以将代码放入同步块中
例::
Synchronized(Object)
{
----Instructions-----
}
我觉得同步块比制作整个方法更好
已同步