1、先从servlet容器提及:你们最为熟悉的servlet容器就是Tomcat ,Servlet 容器是如何管理 Servlet?web
先看一下tomcat的容器模型:数据库
从上图能够看出 Tomcat 的容器分为四个等级,真正管理Servlet 的容器是Context 容器,一个 Context 对应一个 Web 工程编程
Tomcat 的容器等级中,Context 容器是直接管理 Servlet 在容器中的包装类Wrapper(StandardWrapper)的容器,因此 Context 容器如何运行将直接影响 Servlet 的工做方式。tomcat
这里解释一下servlet的包装类:StandardWrapper,这里有个疑问,为何要将 Servlet 包装成 StandardWrapper 而不直接是 Servlet 对象。由于StandardWrapper 是 Tomcat 容器中的一部分,它具备容器的特征,而 Servlet 为一个独立的 web 开发标准,不该该强耦合在 Tomcat 中。安全
除了将 Servlet 包装成 StandardWrapper 并做为子容器添加到 Context 中,其它的全部 web.xml 属性都被解析到 Context 中,因此说 Context 容器才是真正运行 Servlet 的 Servlet 容器。一个 Web 应用对应一个 Context 容器,容器的配置属性由应用的 web.xml 指定,这样咱们就能理解 web.xml 到底起到什么做用了服务器
2、下面简述一下servlet的工做工程:网络
Web服务器在与客户端交互时.Servlet的工做过程是:多线程
1. 在客户端对web服务器发出请求app
2. web服务器接收到请求后将其发送给Servletspa
3. Servlet容器为此产生一个实例对象并调用ServletAPI中相应的方法来对客户端HTTP请求进行处理,而后将处理的响应结果返回给WEB服务器.
4. web服务器将从Servlet实例对象中收到的响应结构发送回客户端.
3、servlet的生命周期:
如上图所示,Servlet的生命周期能够分为四个阶段,即装载类及建立实例阶段、初始化阶段、服务阶段和实例销毁阶段。下面针对每一个阶段的编程任务及注意事项进行详细的说明。
一、建立servlet实例:
在默认状况下Servlet实例是在第一个请求到来的时候建立,之后复用。若是有的Servlet须要复杂的操做须要载初始化时完成,好比打开文件、初始化网络链接等,能够通知服务器在启动的时候建立该Servlet的实例。具体配置以下:
<servlet>
<servlet-name>TimeServlet</servlet-name>
<servlet-class>com.allanlxf.servlet.basic.TimeServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
建立servlet对象的相关类结构:
二、初始化
一旦Servlet实例被建立,Web服务器会自动调用init(ServletConfig config)方法来初始化该Servlet。其中方法参数config中包含了Servlet的配置信息,好比初始化参数,该对象由服务器建立。
I.如何配置Servlet的初始化参数?
在web.xml中该Servlet的定义标记中,好比:
<servlet>
<servlet-name>TimeServlet</servlet-name>
<servlet-class>com.allanlxf.servlet.basic.TimeServlet</servlet-class>
<init-param>
<param-name>user</param-name>
<param-value>username</param-value>
</init-param>
<init-param>
<param-name>blog</param-name>
<param-value>http://。。。</param-value>
</init-param>
</servlet>
配置了两个初始化参数user和blog它们的值分别为username和http://。。。, 这样之后要修改用户名和博客的地址不须要修改Servlet代码,只需修改配置文件便可。
II.如何读取Servlet的初始化参数?
ServletConfig中定义了以下的方法用来读取初始化参数的信息:
public String getInitParameter(String name)
参数:初始化参数的名称。
返回:初始化参数的值,若是没有配置,返回null。
III.init(ServletConfig)方法执行次数
在Servlet的生命周期中,该方法执行一次。
IV.init(ServletConfig)方法与线程
该方法执行在单线程的环境下,所以开发者不用考虑线程安全的问题。
V.init(ServletConfig)方法与异常
该方法在执行过程当中能够抛出 ServletException来通知Web服务器Servlet实例初始化失败。一旦ServletException抛出,Web服务器不会将客户 端请求交给该Servlet实例来处理,而是报告初始化失败异常信息给客户端,该Servlet实例将被从内存中销毁。若是在来新的请求,Web服务器会 建立新的Servlet实例,并执行新实例的初始化操做
三、服务
一旦Servlet实例成功建立及初始化,该Servlet实例就能够被服务器用来服务于客户端的请求并生成响应。在服务阶段Web服务器会调用该实例的 service(ServletRequest request, ServletResponse response)方法,request对象和response对象有服务器建立并传给Servlet实例。request对象封装了客户端发往服务器端 的信息,response对象封装了服务器发往客户端的信息。
I. service()方法的职责
service()方法为Servlet的核心方法,客户端的业务逻辑应该在该方法内执行,典型的服务方法的开发流程为:
解析客户端请求-〉执行业务逻辑-〉输出响应页面到客户端
II.service()方法与线程
为了提升效率,Servlet规范要求一个Servlet实例必须可以同时服务于多个客户端请求,即service()方法运行在多线程的环境下,Servlet开发者必须保证该方法的线程安全性。
III.service()方法与异常
service()方法在执行的过程当中能够抛出ServletException和IOException。其中ServletException能够在 处理客户端请求的过程当中抛出,好比请求的资源不可用、数据库不可用等。一旦该异常抛出,容器必须回收请求对象,并报告客户端该异常信息。 IOException表示输入输出的错误,编程者没必要关心该异常,直接由容器报告给客户端便可。
编程注意事项说明:
1) 当Server Thread线程执行Servlet实例的init()方法时,全部的Client Service Thread线程都不能执行该实例的service()方法,更没有线程可以执行该实例的destroy()方法,所以Servlet的init()方法 是工做在单线程的环境下,开发者没必要考虑任何线程安全的问题。
2) 当服务器接收到来自客户端的多个请求时,服务器会在单独的Client Service Thread线程中执行Servlet实例的service()方法服务于每一个客户端。此时会有多个线程同时执行同一个Servlet实例的 service()方法,所以必须考虑线程安全的问题。
3) 请你们注意,虽然service()方法运行在多线程的环境下,并不必定要同步该方法。而是要看这个方法在执行过程当中访问的资源类型及对资源的访问方式。分析以下:
i. 若是service()方法没有访问Servlet的成员变量也没有访问全局的资源好比静态变量、文件、数据库链接等,而是只使用了当前线程本身的资源, 好比非指向全局资源的临时变量、request和response对象等。该方法自己就是线程安全的,没必要进行任何的同步控制。
ii. 若是service()方法访问了Servlet的成员变量,可是对该变量的操做是只读操做,该方法自己就是线程安全的,没必要进行任何的同步控制。
iii. 若是service()方法访问了Servlet的成员变量,而且对该变量的操做既有读又有写,一般须要加上同步控制语句。
iv. 若是service()方法访问了全局的静态变量,若是同一时刻系统中也可能有其它线程访问该静态变量,若是既有读也有写的操做,一般须要加上同步控制语句。
v. 若是service()方法访问了全局的资源,好比文件、数据库链接等,一般须要加上同步控制语句。
四、销毁
当Web服务器认为Servlet实例没有存在的必要了,好比应用从新装载,或服务器关闭,以及Servlet很长时间都没有被访问过。服务器能够从内存 中销毁(也叫卸载)该实例。Web服务器必须保证在卸载Servlet实例以前调用该实例的destroy()方法,以便回收Servlet申请的资源或 进行其它的重要的处理。
Web服务器必须保证调用destroy()方法以前,让全部正在运行在该实例的service()方法中的线程退出或者等待这些线程一段时间。一旦 destroy()方法已经执行,Web服务器将拒绝全部的新到来的对该Servlet实例的请求,destroy()方法退出,该Servlet实例即 能够被垃圾回收。
4、servlet解析客户端http请求流程图:
1. web客户向Servlet容器发出HTTP请求;
2. Servlet容器解析web的HTTP请求.
3. Servlet容器建立一个HttpRequest对象,在这个对象中封装了http请求信息;
4. Servlet容器建立一个HttpResponse对象;
5. Servlet容器(若是访问的该servlet不是在服务器启动时建立的,则先建立servlet实例并调用init()方法初始化对象)调用HttpServlet的service()方法,把HttpRequest和HttpResponse对象为service方法的参数传给HttpServlet对象;
6. HttpServlet调用HttpRequest的有关方法,获取HTTP请求信息;
7. HttpServlet调用HttpResponse的有关方法,生成响应数据;
8. Servlet容器把HttpServlet的响应结果传给web客户.