How Tomcat works 之 StandardWrapper 标准包装

在第五章中 已经料及了有四种类型的容器:引擎,主机,上下文和包装。你在前面的章节中也建立了自己的简单地上下文和包装。一个上下文通常有一个或更多的包装,每个包装代表一个Servlet定义。这章将查看CatalinaWrapper接口的标准实现。以被每个HTTP请求调用的方法顺序开始并接着讲解javax.servlet.SingleThreadModel接口。这章主要讲解了StandardWrapper和StandardWrapperValue类。并使用StandardWrapper实例代表Servlet。


Sequence of Methods  Invocation 方法调用顺序


对于每个到来的HTTP 请求,连接器调用相关容器的invoke方法。例如,如果连接器关联一个StandardContext的实例,连接器将调用StandardContext实例的invoke方法,稍后会调用它的子容器的所有invoke方法(在这种情况下,子容器将会是StandardWrapper类型)。图1.1演示了当连接器接受一个HTTP请求将发生什么。(回顾第五章中一个容器有一个包含一个或多个Value的管道)




                   1   连接器创建请求和响应对象

                   2   连接器调用StandardContext实例的invoke方法

                   3  StandardContext的invoke方法反过来调用上下文管道的invoke方法。StandardContext的管道的基本值是一个StandardContextValue,所以又调用StandardContextValue的invoke方法。

                   4  StandardContextValue的invoke方法获取合适的Wrapper来服务请求并调用wrapper的invoke方法。

                   5  StandardWrapper是一个wrapper的标准的实现类。StandardWrapper实例的invoke方法调用它的管道的invoke方法。

                   6  StandardWrapper管道的basic Value 是一个StandardWrapperValue。因此它的invoke方法被调用。其invoke方法调用wrapper的allocate方法来获取一个Servlet实例。

                  7 allocate方法调用load方法加载Servlet,如果Servlet需要被加载的话。

                 8  load方法调用Servlet的init方法

                 9  StandardWrapperValue调用Servlet的service方法


注意  StandardContext类的构造器设置了StandardContextValue的实例作为其基本值。


                 public  StandardContext() {

                          super();
                          pipeline.setBasic(new StandardContextValve());
                          namingResources.setContainer(this);
                 } 


注意 StandardWrapper类的构造器设置SimpleWrapperValue的实例作为其基本值

                 public StandardWrapper() {
                                super();
                                pipeline.setBasic(new StandardWrapperValve());
                 } 


在这一章我 我们对于Servlet如何被调用感兴趣。因此我们将查看StandardWrapper和StandardWrapperValue类。在这之前,先看javax.servlet.SingleThreadModel接口。理解这个接口对于理解一个wrapper如何加载一个Servlet至关重要。



SingleThreadModel

一个Servlet可以实现SingleThreadModel接口。实现这个接口的饿实例就被叫做一个STM 即SingleThreadModel Servlet。按照Servlet规范,实现这个接口的目的是保证这个Servlet在某个时间只能处理一个请求。下面是Servlet 2.4规范的一部分:

                           如果一个Servlet实现了这个接口,你就保证了在Servlet的service方法中不会有两个线程同步执行。Servlet容器能保证这个  通过同步访问这个Servlet的单一实例,或者通过维持池化的Servlet实例并拦截每个新的请求分给一个空闲的Servlet。这个接口不能阻止同步问题导致servlets访问共享资源,比如静态类变量或者超出Servlet范围的类。


许多程序员不仔细读这些,认为实现SimpleThreadModel将保证他们的Servlet线程安全。这不是一个个案。仔细再读一遍上述的引用。


实现SimpleThreadModel将保证在同一时间没有两个线程可以执行Servlet的service方法。然而,为保证执行效率,Servlet容器能创建一个STM  Servlet的多个实例。那意味着,STM Servlet的service方法能在不同的实例中并发执行。这里将介绍同步问题,如果Servlet需要访问静态类变量或者超出类范围的其他资源。

 

多线程安全的错误理解     

SimpleThreadModel在Servlet2.4中被废弃了。因为它使Servlet开发人员 对于多线程安全错误理解。然而,Servlet2.3和servlet2.4容器仍必须支持这个接口。    


StandardWrapper


StandardWrapper对象的主要任务是加载它负责的Servlet并分配它的一个实例。然而 StandardWrapper不调用Servlet的service方法。这个任务留给StandardWrapperValue对象,由StandardWrapper实例的管道的基本值完成。StandardWrapperValue对象调用StandardWrapper的allocate方法从StandardWrapper获取Servlet实例。一旦获取了Servlet的实例,StandardWrapperValue调用了Servlet的service方法。


当Servlet第一次被请求的时候,StandardWrapper加载Servlet类。StandardWrapper动态加载一个Servlet。因此它需要知道这个Servlet类的完全限定名。你通过传递Servlet类名给StandardWrapper的setServletClass方法来告诉它这个。另外,你调用它的setName方法传递这个Servlet将涉及的名字。


对于当StandardWrapperValue请求它的时候分配的Servlet实例,StandardWrapper必须考虑到这个Servlet是否实现了SimpleThreadModel接口。


对于没有实现SimpleThreadModel接口的Servlet,StandardWrapper将仅加载这个Servlet类一次 并为后面的请求继续返回同样的实例。StandardWrapper实例不需要Servlet的多实例,因为它假定对于多线程调用Servlet的service方法是安全的。如果有必要,这是Servlet程序员的责任来同步访问一个公共资源。


对于一个STM Servlet,事情就不同了。StandardWrapper必须保证不会有两个线程将同时访问STM Servlet的service方法。如果一个StandardWrapper维护这个STM Servlet的单一实例,这里就是它将如何调用STM Servlet的service方法:


      Servlet instance = <get an instance of the servlet>;
          if ((servlet implementing SingleThreadModel>)              {
              synchronized (instance) {
                   instance.service(request, response);
                    }
            }
           else {
                    instance.service(request, response);
             } 


然而考虑到性能,StandardWrapper维护了一组池化的Servlet实例。


一个wrapper也负责准备一个javax.serlvet.ServletConfig实例,这个可以从Servlet内部获取。下面部分讨论了分配和加载这个Servlet。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值