Tomcat设计模式-责任链模式(二)pipeline valve

来源:互联网 发布:手机淘宝如何给差评 编辑:程序博客网 时间:2024/06/06 02:11

在tomcat中责任链模式还有一个非常典型的应用:http消息在container之间的传递。

具体过程在文章Tomcat源码分析HTTP消息处理(从connectorservlet中已经详细分析过,本文着重分析容器间管道和阀门的实现。

Tomcat源码分析HTTP消息处理(从connectorservlet中提到,消息传递过程中每个容器内都会有这样一样代码:

xxxx. getPipeline().getFirst().invoke(request, response);

这里就是通过管道对阀的调用。下面分析阀是怎么加入到管道并连接起来的。这里举例分析Host容器,其他容器过程与Host相同。

1.      为容器加入管道

在容器的基类ContainerBase 中用成员变量

protected Pipeline pipeline =        CatalinaFactory.getFactory().createPipeline(this);public class CatalinaFactory {        private static CatalinaFactory factory = new CatalinaFactory();        public static CatalinaFactory getFactory() {        return factory;    }        private CatalinaFactory() {        // Hide the default constructor    }        public String getDefaultPipelineClassName() {        return StandardPipeline.class.getName();    }    public Pipeline createPipeline(Container container) {        Pipeline pipeline = new StandardPipeline();        pipeline.setContainer(container);        return pipeline;    }}

由此,每个容器都有一个StandardPipeline类型的pipeline

2. pipeline设置基本的阀门

public StandardHost() {        super();        pipeline.setBasic(new StandardHostValve()); }

basicValveinvoke中会调用下一个容器。

3. 增加阀门

getPipeline().addValve(valve);

 

StandardPipeline中会保存firstbasic两个阀门,新加阀门会增加到basic之前。valve本身是一个单向链表,会保存next

        // Add this Valve to the set associated with this Pipeline        if (first == null) {        first = valve;        valve.setNext(basic);        } else {            Valve current = first;            while (current != null) {if (current.getNext() == basic) {current.setNext(valve);valve.setNext(basic);break;}current = current.getNext();}        }

通过2,3两步,pipeline中增加了一个从firstbasicvalve列表。

4. 阀门的调用

valve的基类ValveBase中有虚方法

publicabstractvoid invoke(Requestrequest, Response response)

       throws IOException,ServletException;

                每个子类都会实现这个方法,这里面完成需要的valve逻辑。这里作为basicValve在invoke中会调用下一个容器。其他容器都必须调用getNext().invoke(request,response);除非想特意让pipeline中断,转到你需要的容器中。

5.      加入第三方valve

可以通过继承ValveBase或者org.apache.catalina.valves中的类实现自己的valve。这里要特别注意,如果不想改变消息的传递方向的话,在实现invoke方法时一定要加入getNext().invoke(request,response)。

还需要在server.xml中给容器增加valve配置,如:


<Engine defaultHost="localhost" name="Catalina">    <Valve className="org.apache.catalina.valves.RequestDumperValve"/>    ………    <Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true"             xmlNamespaceAware="false" xmlValidation="false">        <Valve className="org.apache.catalina.valves.FastCommonAccessLogValve"            directory="logs"  prefix="localhost_access_log." suffix=".txt"            pattern="common" resolveHosts="false"/>               …………    </Host></Engine>

以上,pipeline-valve的原理和增加方法就分析完了。通过pipeline-valve,tomcat的使用者不仅可以完成消息过滤,还可以改变消息的流向。在不改变tomcat原来逻辑的情况下实现扩展tomcat。

 



原创粉丝点击