深入剖析Tomcat - Servlet容器
您目前处于:技术核心竞争力  2014-07-15

Servlet 容器是用来处理请求 servlet 资源,并为 Web 客户端填充 response 对象的模块。servlet 容器是org.apache.catalina.Container 接口的实例。在 Tomcat 中,共有4中类型的容器:Engine、Host、Context和Wrapper。

Container接口

Tomcat 中的 servlet 容器必须要实现 org.apache.catalina.Container 接口。对于 Catalina 中的 servlet 容器,首先需要注意的是,共有4种类型的容器,分别对应不同的概念层次:

Engine:表示整个 Catalina servlet 引擎
Host:表示包含有一个或多个 Context 容器的虚拟主机
Context:表示一个 Web 应用程序。一个 Context 可以有多个 Wapper
Wrapper:表示一个独立的 Servlet

上述的每个概念层次都由 org.apache.catalina 包内的一个接口表示,这些接口分别是 Engine、Host、Context 和 Wrapper,它们都继承自 Container 接口。这4个接口的标准实现分别是 StandardEngine 类、StandardHos t类、StandardContext 类和 StandardWrapper 类,它们都在 org.apache.catalina.core 包内。

管道任务

管道包含 Servlet 容器将要调用的任务,一个阀表示一个具体的执行任务。管道就像是过滤器链,而阀就像是过滤器。阀与过滤器类似,可以处理传递给它的 request 对象和 response 对象。当一个阀执行完成后,会调用下一个阀继续执行。基础阀总会是最后一个执行的。

当调用了容器的 invoke() 方法后,容器会将处理工作交由管道完成,而管道会调用其中的第1个阀开始处理。当第1个阀处理完成后,它会调用后续的阀继续执行任务,直到管道中所有的阀都处理完成。

// invoke each value added to the pipeline
for(int n = 0; n < values.length; n++) {
    values[n].invoke( ... );
}
// then, invoke the basic value
basicValue.invoke( ... );

Tomcat 通过引入接口 org.apache.catalina.ValueContext 来实现阀的遍历执行。当连接器调用容器的 invoke() 方法后,容器中要执行的任务并没有硬编码写在 invoke() 方法中。相反容器会调用其管道的 invoke() 方法。

public void invoke(Request request, Response response) 
                throws IOException, ServletException {
    pipeline.invoke(request, response);
}

管道必须保证添加到其中的所有阀及其基本阀都被调用一次,这是通过创建个 ValueContext 接口实例来实现的。创建 ValueContext 实例后,管道会调用 ValueXOntext 实例的 invokeNext() 方法。

public void invoke(Request request, Response response, ValueContext valueContext) 
                throws IOException, ServletException {
    // Pass the request and response on to the next value in our pipeline
    valueContext.invokeNext(request, response);
    // now perform what this value is supposed to do
    // ...
}

org.apache.catalina.core.StandarPipeline 类是所有 Servlet 容器中的 Pipeline 接口的实现。

protected class StandardPipelineValueContext implements ValueContext {
    protected int stage = 0;
    
    public String getInfo() {
        return info;
    }

    public void invokeNext(Request request, Response response) 
                throws IOException, ServletException {
        int subscript = stage;
        stage = stage + 1;
        // Invoke the requested Value for the current request thread
        if(subscript < values.length) {
            values[subscript].invoke[request, response , this);
        } else if((subscript == values.length) && (basic != null)) {
            basic.invoke(request, response, this);
        } else {
            throw new ServletException(sm.getString("standardPipeline.noValue"));
        }
    }
}

Tomcat5 从 StandardPipeline 类中移除了 StandardPipelineValueContext 类,使用 org.apache.catalina.core.StandardValueContext 类来调用阀。

public final class StandardValueContext implements ValueContext {
    protected static String Manager sm = StringManager.getmanager(Constants.Package);
    protected String info = "org.apache.catalina.core.StandardValueContext/1.0";
    protected int stage = 0;
    protected Value basic = null;
    protected Value values[] = null;
    
    public String getInfo() {
        return info;
    }

    public final void invokeNext(Request request, Response response) 
                throws IOException, ServletException {
        int subscript = stage;
        stage = stage + 1;
        // Invoke the requested Value for the current request thread
        if(subscript < values.length) {
            values[subscript].invoke[request, response , this);
        } else if((subscript == values.length) && (basic != null)) {
            basic.invoke(request, response, this);
        } else {
            throw new ServletException(sm.getString("standardPipeline.noValue"));
        }
    }

    void set(Value basic, Values values[]) {
        stage = 0;
        this.basic = basic;
        this.values = values;
    }
}

Pipeline 接口

public interface Pipeline {
    public Value getBasic;
    public void setBasic(Value value);
    public void addValue(Value value);
    public Value[] getValuse();
    public void invoke(Request request, Response response) 
                throws IOException, ServletException;
    public void removeValue(Value value);
}

Value 接口

public interface Value {
    public String getInfo();
    public void invoke(Request request, Response response, ValueContext context) 
                throws IOException, ServletException;
}

ValueContext 接口

public interface ValueContext {
    public String getInfo();
    public void invokeNext(Request request, Response response) 
                throws IOException, ServletException;
}

Contained 接口

public interface Contained {
    public Container getContainer();
    public void setContainer(Container container);
}

Wrapper 接口

Wrapper级的Servlet容器是一个org.apache.catalina.Wrapper接口的实例,表示一个独立的servlet定义。Wrapper 接口继承自 Container 接口,又添加了一些额外的方法。Wrapper 接口的实现类要负责管理其基础 Servlet 类的 Servlet 生命周期,即调用 Servlet 的 init()、service()、destroy() 等方法。由于 Wrapper 已经是最低级的 Servelt 容器,因此不能再向其添加子容器。若是 Wrapper 的 addChild() 方法被调用,则抛出 IllegalArgumantException 异常。


转载请并标注: “本文转载自 linkedkeeper.com ”  ©著作权归作者所有