Tomcat 容器模型
从上图可以看出 Tomcat 的容器分为四个等级,真正管理 Servlet 的容器是 Context 容器,一个 Context 对应一个 Web 工程,在 Tomcat 的配置文件(server.xml) 中可以很容易发现这一点,如下:
1<Context path="/projectxxx " docBase= "D:projectsprojectxxx" reloadable="true" />
下面详细介绍一下 Tomcat 解析 Context 容器的过程,包括如何构建 Servlet 的过程。既然接口是连接 Servlet 与 Servlet 容器的关键,那我们就从它们的接口说起。
1.Servlet 容器的启动过程
创建一个Tomcat的一个实例对象,新增了一个WEB应用 (Tomcat的addWebap方法 ),并调用start方法就可以启动 tomcat。
1Tomcat tomcat = getTomcatInstance();
2File appDir = new File(getBuildDirectory(), "webapps/examples");
3tomcat.addWebapp(null, "/examples", appDir.getAbsolutePath());
4tomcat.start();
1public Context addWebapp(Host host, String url, String path) {
2 silence(url);
3 Context ctx = new StandardContext();
4 ctx.setPath( url );
5 ctx.setDocBase(path);
6 if (defaultRealm == null) {
7 initSimpleAuth();
8 }
9 ctx.setRealm(defaultRealm);
10 ctx.addLifecycleListener(new DefaultWebXmlListener());
11 ContextConfig ctxCfg = new ContextConfig();
12 ctx.addLifecycleListener(ctxCfg);
13 ctxCfg.setDefaultWebXml("org/apache/catalin/startup/NO_DEFAULT_XML");
14 if (host == null) {
15 getHost().addChild(ctx);
16 } else {
17 host.addChild(ctx);
18 }
19 return ctx;
20}
一个 Web 应用对应一个 Context 容器,也就是 Servlet 运行时的 Servlet 容器。
添加一个 Web 应用时将会创建一个 StandardContext 容器,并且给这个 Context 容器设置必要的参数,url 和 path 分别代表这个应用在 Tomcat 中的访问路径和这个应用实际的物理路径,这两个参数与 Tomcat 配置中的两个参数是一致的。
其中最重要的一个配置是 ContextConfig,ContextConfig 类 负责整个WEB应用的配置文件的解析工作,后面将会详细介绍。
最后将这个 Context 容器加到父容器 Host 中。接下去将会调用 Tomcat 的 start 方法启动 Tomcat。
◆
2.Web应用的初始化工作
WEB应用的初始化工作是在 ContextConfig 的 configureStart 方法中实现的,应用的初始化工作主要是解析 web.xml文件,这个文件是一个WEB应用的入口。
Tomcat 首先会找 globalWebXml,以及应用的配置文件 web.xml 文件中的各个配置项将会被解析成相应的属性保存在 WebXml 对象中。接下来会将 WebXml 对象中的属性设置到 context 容器中,这里包括创建 Servlet 对象,filter,listerner等。
将 Servlet 容器包装成 context 容器中的 StandardWrapper。
StandardWrapper 是 Tomcat 容器中的一部分,它具有容器的特征,而 Servlet 作为一个独立的 web 开发标准,不应该强制耦合在Tomcat中。
◆
3.创建Servlet对象
前面完成了Servlet 的解析工作,并且被包装成了 StandardWrapper 添加到Context 容器中,但是它仍然不能为我们工作,它还没有被实例化。
如果Servlet的 load-on-startup 配置项大于 0,那么在Context容器启动时就会被实例化。
前面提到的在解析配置文件时会读取默认的 globalWebXml ,在conf 下的web.xml 文件中定义了一些默认的配置项,其中定义了两个Servlet,分别是org.apache.catalina.servlets.DefaultServlet 和 org.apache.jsper.Servlet .JspServelt,它们的 load-on-startup 分别是1和3,也就是当 tomcat 启动时这两个Servlet 就会被启动。
创建 Servlet 实例的方式是从 Wrapper.loadServlet 开始的,loadServlet 方法要完成的就是获取 servletClass,然后把它交给 InstanceManager 去创建一个基于 servletClass.class 的对象。
◆
4.初始化Servlet对象
初始化 Servlet 在 StandardWrapper 的 initServlet() 方法中,这个方法很简单,就是调用 Servlet 的 init()方法,同时把包装了 StandardWrapper 对象的 StandardWrapperFacade 作为 ServletConfig传给 Servlet。
如果该 Servlet 关联的是一个 JSP 文件,那么前面初始化的就是 JspServlet,接下来会模拟一次简单请求,请求调用这个JSP文件,以便编译这个JSP文件为类,并初始化这个类。
这样Servlet对象的初始化就完成了。