责任链模式:责任链模式可以用在这样的场景,当一个request过来的时候,需要对这个request做一系列的加工,使用责任链模式可以使每个加工组件化,减少耦合。也可以使用在当一个request过来的时候,需要找到合适的加工方式。当一个加工方式不适合这个request的时候,传递到下一个加工方法,该加工方式再尝试对request加工。
在tomcat中容器之间的调用使用的就是责任链的设计模式,当一个请求过来的时候首先是engine容器接受请求,然后engine容器会把请求传到host容器,host容器又会传到context容器,context容器传到wrapper容器,最后wrapper容器使用适配请求的servlet处理请求。tomcat实现容器间的责任传递主要涉及到这三个接口:Container,Pipeline,Valve.看下这三者的关系,以StandardEngine为例:
其中ContainerBase实现自Container,图中为了简洁没有标示出来。
valve中有三个关键的方法:
public Valve getNext(); // 返回下一个valve public void setNext(Valve valve); // 设置下一个valve public void invoke(Request request, Response response) throws IOException, ServletException; // invoke为实际要执行的代码
Container中有一个关键方法:
public Pipeline getPipeline(); // 获取一个阀门管道
当一个请求过来的时候,会调用StandardEngine中的getPipeline,然后依次执行其中valve;
初始开始的代码在CoyteAdapter的407行,如下:
connector.getService().getContainer().getPipeline().getFirst().invoke(request, response);
connector.getService().getContainer()获得是的StandardEngine的实例。
假设最后要访问的servlet为TestServlet可以看到有如下调用。
从StandardEngineValve中会一直调用到standardWrapperValve。tomcat的容器之间的调用就是通过这种方式来调用的。这样带来的好处就是,如果容器中需要新加一个阀门,只需要创建这个阀门,并且添加到pipeline中即可,不会影响到其他阀门代码,也不需要修改外部调用容器执行pipeline的代码