Tomcat中一共有四种容器:engine(引擎),host(主机),context(上下文)和wrapper(包装器)。在前面的章节里也介绍了如何建立自己的context和wrapper。一个上下文一般包括一个或者多个包装器,每一个包装器表示一个servlet。本章将会看到Catalina中Wrapper接口的标准实现。首先介绍了一个HTTP请求会唤醒的一系列方法,接下来介绍了javax.servlet.SingleThreadModel接口。最后介绍了StandardWrapper和StandardWrapperValve类。
方法调用序列
对于每一个连接,连接器都会调用关联容器的invoke方法。接下来容器调用它的所有子容器的invoke方法。例如,如果一个连接器跟一个StadardContext实例相关联,那么连接器会调用StandardContext实例的invoke方法,该方法会调用所有它的子容器的invoke方法
1、连接器创建请求和响应对象
2、连接器调用StandardContext的invoke方法
3、StandardContext的invoke方法必须调用该上下文容器的流水线的invoke方法,所以StandardContext的流水线会调用StandardContextValve的invoke方法
4、StandardContextValve的invoke方法得到合适的包装器来对请求进行服务并调用包装器的invoke方法
5、StandardWrapper是包装器的标准实现,StandardWrapper对象的invoke方法调用流水线的invoke方法。
6、StandardWrapper流水线的基本阀门是StandardWrapperValve。因此StandardWrapperValve的invoke方法会被调用。StandardWrapperValve的invoke方法会调用包装器的allocate方法获得一个servlet的实例。
7、当一个servlet需要被加载的时候,方法allocate调用方法load来加载一个servlet
8、方法load会调用servlet的init方法
StandardContext类的构造函数设置StandardContextValve实例为它的基本阀门
StandardWrapper类的构造函数将StandardWrapperValve作为它的基本阀门
SingleThreadModel
一个servlet可以实现javax.servlet.SingleThreadModel接口,实现此接口的一个servlet通俗称为SingleThreadModel(STM)的程序组件。根据Servlet规范,实现此接口的目的是保证servlet一次只能有一个请求。
如果一个Servlet实现此接口,将保证不会有两个线程同是使用servlet的service方法。 servlet容器可以保证同步进入一个servlet的一个实例,或维持的Servlet实例池和处理每个新请求。该接口并不能避免同步而产生的问题,如访问静态类变量或该servlet以外的类或变量。
一个servlet实现了SIngelThreadModel之后确实能保证它的service方法不会被两个线程同时使用。为了提高servlet容器的性能,可以创建STM servlet的多个实例。
StandardWrapper
一个StandardWrapper对象的主要职责是:加载它表示的servlet并分配它的一个实例。该StandardWrapper不会调用servlet的service方法。这个任务留给StandardWrapperValve对象,在StandardWrapper实例的基本阀门管道。StandardWrapperValve对象通过调用StandardWrapper的allocate方法获得Servlet实例。在获得Servlet实例之后的StandardWrapperValve调用servlet的service方法
在servlet第一次被请求的时候,StandardWrapper加载servlet类。它是动态的加载servlet,所以需要知道servlet类的完全限定名称。通过StandardWrapper类的setServletClass方法将servlet的类名传递给StandardWrapper。另外,使用setName方法也可以传递servlet名。
考虑到StandardWrapper负责在StandardWrapperValve请求的时候分配一个servlet实例,它必须考虑一个servlet是否实现了SingleThreadModel接口。 如果一个servlet没有实现SingleThreadModel接口,StandardWrapper加载该servlet一次,对于以后的请求返回相同的实例即可。StandardWrapper假设servlet的service方法是线程安全的,所以并没有创建servlet的多个实例。如果需要的话,由程序员自己解决资源同步问题。
对于一个STM servlet,情况就有所不同了。StandardWrapper必须保证不能同时有两个线程提交STM servlet的service方法。如果StandardWrapper维持一个STM servlet的实例,下面是它如何调用servlet的service方法:
StandardWrapper维护了一个STM servlet实例池。 一个包装器还负责准备一个javax.servlet.ServletConfig的实例,这可以在servlet内部完成。
Allocating the Servlet
&nb