Servlet原理 一:Servlet容器
注:在网上看到一篇文章--《Servlet工作原理》,整理并做了一些笔记
1. 了解 Servlet 容器
首先,要从servlet 容器开始。servlet容器,故名思议,就是装载和管理Servlet的服务端程序。借用一个前辈的解释:Servlet与Servlet容器的关系有点像枪和子弹的关系,枪是为子弹而生,而子弹又让枪有了杀伤力。
下图是Tomcat容器模型:
![](https://img.haomeiwen.com/i1907552/04324ebfdd2ae062.png)
可以看出 Tomcat 的容器分为四个等级,真正管理 Servlet 的容器是 Context 容器,一个 Context 对应一个 Web 工程, Context 容器如何运行将直接影响 Servlet 的工作方式。
2. Servlet 容器启动过程
![](https://img.haomeiwen.com/i1907552/1223bb1b690d2731.png)
Tomcat7 支持嵌入式功能,增加了一个启动类 org.apache.catalina.startup.Tomcat。创建一个实例对象并调用 start 方法就可以很容易启动 Tomcat,还可以通过这个对象来增加和修改 Tomcat 的配置参数。下面我们就利用这个 Tomcat 类来管理新增的一个 Context 容器,我们就选择 Tomcat7 自带的 examples Web 工程,并看看它是如何加到这个 Context 容器中的。
# 创建一个 Tomcat 实例
Tomcat tomcat = getTomcatInstance();
File appDir = new File(getBuildDirectory(), "webapps/examples");
# 新增一个 Web 应用
tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath());
# 启动 Tomcat
tomcat.start();
# 调用其中的一个 HelloWorldExample Servlet,看有没有正确返回预期的数据。
ByteChunk res = getUrl("http://localhost:" + getPort() +
"/examples/servlets/servlet/HelloWorldExample"); assertTrue(res.toString().indexOf("<h1>Hello World!</h1>") > 0);
一个 Web 应用对应一个 Context 容器,也就是 Servlet 运行时的 Servlet 容器,添加一个 Web 应用时将会创建一个 StandardContext 容器(StandardContext是Context的标准实现),并且给这个 Context 容器设置必要的参数,url 和 path 分别代表这个应用在 Tomcat 中的访问路径和这个应用实际的物理路径。其中最重要的一个配置是 ContextConfig,这个类将会负责整个 Web 应用配置的解析工作。最后将这个 Context 容器加到父容器 Host 中。
接下去将会调用 Tomcat 的 start 方法启动 Tomcat,Tomcat 的启动逻辑是基于观察者模式设计的,所有的容器都会继承 Lifecycle 接口,它管理者容器的整个生命周期,所有容器的的修改和状态的改变都会由它去通知已经注册的观察者(Listener)。
当 Context 容器初始化状态设为 init 时,添加在 Contex 容器的 Listener 将会被调用。ContextConfig 继承了 LifecycleListener 接口,它是在调用 addWebapp 时被加入到 StandardContext 容器中。ContextConfig 类会负责整个 Web 应用的配置文件的解析工作。
ContextConfig 的 init 方法将会主要完成以下工作:
1. 创建用于解析 xml 配置文件的 contextDigester 对象
2. 读取默认 context.xml 配置文件,如果存在解析它
3. 读取默认 Host 配置文件,如果存在解析它
4. 读取默认 Context 自身的配置文件,如果存在解析它
5. 设置 Context 的 DocBase
ContextConfig 的 init 方法完成后,Context 容器的会执行 startInternal 方法,这个方法启动逻辑比较复杂,主要包括如下几个部分:
1. 创建读取资源文件的对象
2. 创建 ClassLoader 对象
3. 设置应用的工作目录
4. 启动相关的辅助类如:logger、realm、resources 等
5. 修改启动状态,通知感兴趣的观察者(Web 应用的配置)
6. 子容器的初始化
7. 获取 ServletContext 并设置必要的参数
8. 初始化“load on startup”的 Servlet